using System.Globalization; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Forms; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using CtrEditor.Siemens; using static System.Runtime.InteropServices.JavaScript.JSType; using Binding = System.Windows.Data.Binding; using Label = System.Windows.Controls.Label; using MouseEventArgs = System.Windows.Input.MouseEventArgs; using TextBox = System.Windows.Controls.TextBox; using UserControl = System.Windows.Controls.UserControl; using CheckBox = System.Windows.Controls.CheckBox; using Orientation = System.Windows.Controls.Orientation; using ListBox = System.Windows.Controls.ListBox; using CtrEditor.ObjetosSim; namespace CtrEditor { /// /// Interaction logic for MainWindow.xaml /// /// public partial class MainWindow : Window { // Para el Canvas private Point _lastMousePosition; private bool _isDrawingCanvas = false; private bool _isDraggingCanvas = false; private Image imagenDeFondo; // Para los UserControl private Point _startPointUserControl; private UserControl _currentDraggingControl; private bool _isRotatingUserControl = false; private bool _isResizingUserControl = false; private bool _isDraggingUserControl = false; private bool _isMovingUserControl = false; private double _initialAngleUserControl; private TextBlock _angleDisplayTextBlock; public MainWindow() { InitializeComponent(); this.Loaded += MainWindow_Loaded; ImagenEnTrabajoScrollViewer.PreviewMouseWheel += ImagenEnTrabajoCanvas_MouseWheel; ImagenEnTrabajoCanvas.MouseDown += Canvas_MouseDown_Panning; ImagenEnTrabajoCanvas.MouseMove += Canvas_MouseMove_Panning; ImagenEnTrabajoCanvas.MouseUp += Canvas_MouseUp_Panning; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { if (DataContext is MainViewModel viewModel) { viewModel.MainWindow = this; viewModel.ImageSelected += ViewModel_ImageSelected; viewModel?.LoadInitialData(); // Carga la primera imagen por defecto una vez cargada la ventana principal viewModel.simulationManager.DebugCanvas = ImagenEnTrabajoCanvas; viewModel.MainCanvas = ImagenEnTrabajoCanvas; } } public (float X, float Y) ObtenerCentroCanvasPixels() { var scaleTransform = ImagenEnTrabajoCanvas.LayoutTransform as ScaleTransform; float scaleX = (float)(scaleTransform?.ScaleX ?? 1.0); float scaleY = (float)(scaleTransform?.ScaleY ?? 1.0); // Obtiene el área visible del ScrollViewer float visibleWidth = (float)ImagenEnTrabajoScrollViewer.ViewportWidth; float visibleHeight = (float)ImagenEnTrabajoScrollViewer.ViewportHeight; // Obtiene la posición actual del desplazamiento ajustada por el zoom float offsetX = (float)ImagenEnTrabajoScrollViewer.HorizontalOffset / scaleX; float offsetY = (float)ImagenEnTrabajoScrollViewer.VerticalOffset / scaleY; // Calcula el centro visible ajustado float centerX = offsetX + (visibleWidth / scaleX) / 2; float centerY = offsetY + (visibleHeight / scaleY) / 2; return (centerX, centerY); } public (float X, float Y) ObtenerCentroCanvasMeters() { var c = ObtenerCentroCanvasPixels(); return (PixelToMeter.Instance.calc.PixelsToMeters(c.X), PixelToMeter.Instance.calc.PixelsToMeters(c.Y)); } public void SuscribirEventos(UserControl userControl) { userControl.MouseEnter += UserControl_MouseEnter; userControl.MouseLeave += UserControl_MouseLeave; // Suscribir a eventos de mouse para panning userControl.MouseLeftButtonDown += UserControl_MouseLeftButtonDown; userControl.MouseLeftButtonUp += UserControl_MouseLeftButtonUp; userControl.MouseMove += UserControl_MouseMove; } public void AgregarRegistrarUserControlCanvas(UserControl userControl) { if (userControl is IDataContainer dataContainer) { SuscribirEventos(userControl); // Añade el UserControl al Canvas Canvas.SetZIndex(userControl, dataContainer.ZIndex()); ImagenEnTrabajoCanvas.Children.Add(userControl); } } public void EliminarUserControlDelCanvas(UserControl userControl) { if (ImagenEnTrabajoCanvas.Children.Contains(userControl)) { ImagenEnTrabajoCanvas.Children.Remove(userControl); } } private void UserControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (!_isDrawingCanvas) { var userControl = sender as UserControl; _currentDraggingControl = userControl; userControl.CaptureMouse(); // Importante para recibir eventos de movimiento incluso fuera del control _isMovingUserControl = true; if (sender is UserControl control && control.DataContext is osBase datos) { var viewModel = DataContext as MainViewModel; if (viewModel != null) { viewModel.SelectedItemOsList = datos; // Esto desencadenará ListaOs_SelectionChanged } } // ROTACION if (Keyboard.IsKeyDown(Key.LeftShift)) { // Inicializar la rotación _isRotatingUserControl = true; RotateTransform rotateTransform = userControl.RenderTransform as RotateTransform; if (rotateTransform == null) { rotateTransform = new RotateTransform(); userControl.RenderTransform = rotateTransform; } _initialAngleUserControl = rotateTransform.Angle; // Establecer el punto inicial de referencia para el cálculo de rotación _startPointUserControl = new Point(rotateTransform.CenterX, rotateTransform.CenterY); // Ajusta el punto inicial al espacio del Canvas _startPointUserControl = userControl.TranslatePoint(_startPointUserControl, ImagenEnTrabajoCanvas); // Crear y configurar el TextBlock si no existe if (_angleDisplayTextBlock == null) { _angleDisplayTextBlock = new TextBlock { Foreground = Brushes.Black, Background = Brushes.White, Opacity = 0.8, Padding = new Thickness(5) }; ImagenEnTrabajoCanvas.Children.Add(_angleDisplayTextBlock); } PositionAngleDisplay(userControl); _angleDisplayTextBlock.Visibility = Visibility.Visible; Canvas.SetZIndex(_angleDisplayTextBlock, 15); } // TAMANO else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) { // Inicializar el cambio de tamaño _isResizingUserControl = true; } // MOVIMIENTO else { // Inicializar el movimiento/panning _isDraggingUserControl = true; _startPointUserControl = e.GetPosition(ImagenEnTrabajoCanvas); } } } private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (_isMovingUserControl) { var userControl = sender as UserControl; userControl.ReleaseMouseCapture(); _currentDraggingControl = null; _isResizingUserControl = _isRotatingUserControl = _isDraggingUserControl = false ; _isMovingUserControl = false; // Ocultar el TextBlock de ángulo if (_angleDisplayTextBlock != null) { _angleDisplayTextBlock.Visibility = Visibility.Collapsed; } } } private void UserControl_MouseMove(object sender, MouseEventArgs e) { if (_isMovingUserControl && _currentDraggingControl != null) { var currentPosition = e.GetPosition(ImagenEnTrabajoCanvas); if (_isDraggingUserControl) { // Código para mover el control var dx = currentPosition.X - _startPointUserControl.X; var dy = currentPosition.Y - _startPointUserControl.Y; var newX = Canvas.GetLeft(_currentDraggingControl) + dx; var newY = Canvas.GetTop(_currentDraggingControl) + dy; if (_currentDraggingControl is IDataContainer dataContainer) dataContainer.Move((float)newX,(float) newY); _startPointUserControl = currentPosition; // Actualiza el punto inicial para el siguiente movimiento } else if (_isRotatingUserControl) { // Código para rotar el control RotateControl(_currentDraggingControl, currentPosition); } else if (_isResizingUserControl) { // Código para cambiar el tamaño del control ResizeControl(_currentDraggingControl, currentPosition); } } } private void RotateControl(UserControl control, Point currentPosition) { double deltaX = currentPosition.X - _startPointUserControl.X; double deltaY = currentPosition.Y - _startPointUserControl.Y; double angle = Math.Atan2(deltaY, deltaX) * (180 / Math.PI); //RotateTransform rotateTransform = control.RenderTransform as RotateTransform; //rotateTransform.Angle = angle; // - _initialAngleUserControl; // Asegúrate de ajustar esta parte según cómo calcules el ángulo inicial if (control is IDataContainer dataContainer) dataContainer.Rotate((float)angle); // Actualizar el ángulo mostrado _angleDisplayTextBlock.Text = $"Ángulo: {angle:F2}°"; PositionAngleDisplay(control); } private void PositionAngleDisplay(UserControl control) { // Posicionar el TextBlock sobre el control Canvas.SetLeft(_angleDisplayTextBlock, Canvas.GetLeft(control)); Canvas.SetTop(_angleDisplayTextBlock, Canvas.GetTop(control)); } private void ResizeControl(UserControl control, Point currentPosition) { // Calcular la diferencia en la posición X desde el punto de inicio double widthChange = currentPosition.X - _startPointUserControl.X; // Calcular la diferencia en la posición Y desde el punto de inicio double heightChange = currentPosition.Y - _startPointUserControl.Y; // Actualizar el ancho del control double newWidth = Math.Max(control.ActualWidth + widthChange, control.MinWidth); // Actualizar la altura del control double newHeight = Math.Max(control.ActualHeight + heightChange, control.MinHeight); // Asegurar que el nuevo tamaño no sea menor que los mínimos control.Width = newWidth; control.Height = newHeight; if (control is IDataContainer dataContainer) { dataContainer.Resize((float)newWidth, (float)newHeight); } // Actualizar el punto de inicio para el próximo evento de movimiento _startPointUserControl = currentPosition; } private void UserControl_MouseEnter(object sender, MouseEventArgs e) { if (sender is UserControl userControl) if (userControl is IDataContainer dataContainer) dataContainer.Highlight(true); } private void UserControl_MouseLeave(object sender, MouseEventArgs e) { if (sender is UserControl userControl) if (userControl is IDataContainer dataContainer) dataContainer.Highlight(false); } private void ViewModel_ImageSelected(object sender, string imagePath) { LoadImageToCanvas(imagePath); } private void LoadImageToCanvas(string imagePath) { BitmapImage bitmap = new BitmapImage(new Uri(imagePath, UriKind.Absolute)); if (imagenDeFondo == null) { imagenDeFondo = new Image(); ImagenEnTrabajoCanvas.Children.Add(imagenDeFondo); } imagenDeFondo.Source = bitmap; RenderOptions.SetBitmapScalingMode(imagenDeFondo, BitmapScalingMode.HighQuality); // Elimina solo los ROIs, no la imagen de fondo for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--) { if (ImagenEnTrabajoCanvas.Children[i] is not Image) { ImagenEnTrabajoCanvas.Children.RemoveAt(i); } } // Ajusta el tamaño del Canvas a la imagen, si es necesario ImagenEnTrabajoCanvas.Width = bitmap.Width; ImagenEnTrabajoCanvas.Height = bitmap.Height; // Posiciona la imagen correctamente dentro del Canvas Canvas.SetLeft(imagenDeFondo, 0); Canvas.SetTop(imagenDeFondo, 0); } private void Canvas_MouseUp_Panning(object sender, MouseButtonEventArgs e) { if (_isDraggingCanvas) { _isDraggingCanvas = false; ImagenEnTrabajoScrollViewer.ReleaseMouseCapture(); // Finaliza la captura del ratón } } private void Canvas_MouseDown_Panning(object sender, MouseButtonEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas && !_isMovingUserControl) { // Indica que se inicia el panning _isDraggingCanvas = true; // Guarda la posición actual del ratón _lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer); //ImagenEnTrabajoScrollViewer.CaptureMouse(); // Importante para capturar el movimiento } } private void Canvas_MouseMove_Panning(object sender, MouseEventArgs e) { if (_isDraggingCanvas && !_isDrawingCanvas) { // Calcula el nuevo desplazamiento basado en el movimiento del ratón var currentPosition = e.GetPosition(ImagenEnTrabajoScrollViewer); var dx = currentPosition.X - _lastMousePosition.X; var dy = currentPosition.Y - _lastMousePosition.Y; // Ajusta el desplazamiento del ScrollViewer ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(ImagenEnTrabajoScrollViewer.HorizontalOffset - dx); ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(ImagenEnTrabajoScrollViewer.VerticalOffset - dy); // Actualiza la posición del ratón para el próximo movimiento _lastMousePosition = currentPosition; } } private void ImagenEnTrabajoCanvas_MouseWheel(object sender, MouseWheelEventArgs e) { var st = (ScaleTransform)ImagenEnTrabajoCanvas.LayoutTransform; double zoomFactor = e.Delta > 0 ? 1.1 : 0.9; Point cursorPosition = e.GetPosition(ImagenEnTrabajoScrollViewer); // Calcular el punto focal del zoom relativo al contenido del ScrollViewer var absoluteX = ImagenEnTrabajoScrollViewer.HorizontalOffset + cursorPosition.X; var absoluteY = ImagenEnTrabajoScrollViewer.VerticalOffset + cursorPosition.Y; // Aplicar el zoom st.ScaleX *= zoomFactor; st.ScaleY *= zoomFactor; // Calcular el nuevo desplazamiento para que el zoom se centre en la posición del cursor ImagenEnTrabajoScrollViewer.UpdateLayout(); // Asegurarse de que el layout del ScrollViewer esté actualizado var newHorizontalOffset = absoluteX * zoomFactor - cursorPosition.X; var newVerticalOffset = absoluteY * zoomFactor - cursorPosition.Y; // Aplicar el nuevo desplazamiento ImagenEnTrabajoScrollViewer.ScrollToHorizontalOffset(newHorizontalOffset); ImagenEnTrabajoScrollViewer.ScrollToVerticalOffset(newVerticalOffset); e.Handled = true; // Evita el procesamiento adicional del evento } private void ListaOs_SelectionChanged(object sender, SelectionChangedEventArgs e) { //PanelEdicion.Children.Clear(); // Limpiar el panel existente if (e.AddedItems.Count > 0 && e.AddedItems[0] is osBase selectedObject) CargarPropiedadesosDatos(selectedObject); } private void CargarPropiedadesosDatos(osBase selectedObject) { if (DataContext is MainViewModel viewModel) viewModel.CargarPropiedadesosDatos(selectedObject, PanelEdicion, Resources); } private void MainWindow_Closed(object sender, EventArgs e) { if (DataContext is MainViewModel viewModel) { viewModel.ImageSelected -= ViewModel_ImageSelected; } } } public class FloatValidationRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { // Comprobamos si el valor es nulo o está vacío if (string.IsNullOrEmpty(value?.ToString())) return new ValidationResult(false, "El campo no puede estar vacío."); // Intentamos convertir el valor a un tipo float if (float.TryParse(value.ToString(), NumberStyles.Float, cultureInfo, out float result)) return ValidationResult.ValidResult; // La validación es exitosa else return new ValidationResult(false, "Ingrese un número válido."); } } }