From 38ca212d9f6e1cab7283232281ba0047f69f5d5a Mon Sep 17 00:00:00 2001 From: Miguel Date: Wed, 19 Feb 2025 21:27:33 +0100 Subject: [PATCH] Agregado movimiento con flechas de los objetos seleccionados --- MainWindow.xaml | 14 ++++- MainWindow.xaml.cs | 115 +++++++++++++++++++++++++++++++++-- ObjectAlignment.cs | 104 ++++++++++++++++++++----------- ObjectManipulationManager.cs | 4 ++ 4 files changed, 195 insertions(+), 42 deletions(-) diff --git a/MainWindow.xaml b/MainWindow.xaml index f54816e..8f12648 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -153,9 +153,17 @@ - - + + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index b071b6d..157d689 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -151,6 +151,7 @@ namespace CtrEditor // y no en otros controles if (e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo) { + ImagenEnTrabajoCanvas.Focus(); // Asegurar que el canvas tiene el foco _isDraggingCanvas = true; _lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer); ImagenEnTrabajoCanvas.CaptureMouse(); @@ -259,6 +260,7 @@ namespace CtrEditor private void ListaOs_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { + ImagenEnTrabajoCanvas.Focus(); // Asegurar que el canvas tiene el foco UserControlFactory.LimpiarPropiedadesosDatos(PanelEdicion); if (e.AddedItems.Count > 0 && e.AddedItems[0] is osBase selectedObject) @@ -285,6 +287,12 @@ namespace CtrEditor private void MainWindow_KeyDown(object sender, KeyEventArgs e) { + // Forzar el foco al canvas si no lo tiene + if (!ImagenEnTrabajoCanvas.IsFocused) + { + ImagenEnTrabajoCanvas.Focus(); + } + if (DataContext is MainViewModel viewModel) { if (e.Key == Key.Delete) @@ -294,16 +302,55 @@ namespace CtrEditor } else if (e.Key == Key.Escape) { - // Limpiar la selección en el ListBox viewModel.SelectedItemOsList = null; - - // Limpiar la selección múltiple _objectManager.ClearSelection(); _objectManager.RemoveResizeRectangles(); - - e.Handled = true; } + else if (_objectManager.SelectedObjects.Any()) + { + const float moveDistance = 0.1f; + switch (e.Key) + { + case Key.Left: + MoveSelectedObjects(-moveDistance, 0); + e.Handled = true; + break; + case Key.Right: + MoveSelectedObjects(moveDistance, 0); + e.Handled = true; + break; + case Key.Up: + MoveSelectedObjects(0, -moveDistance); + e.Handled = true; + break; + case Key.Down: + MoveSelectedObjects(0, moveDistance); + e.Handled = true; + break; + } + } + } + } + + private void MoveSelectedObjects(float deltaX, float deltaY) + { + // Mover todos los objetos primero + foreach (var obj in _objectManager.SelectedObjects) + { + obj.Left += deltaX; + obj.Top += deltaY; + } + + // Forzar una actualización del layout antes de actualizar los visuales + ImagenEnTrabajoCanvas.UpdateLayout(); + + // Ahora actualizar los visuales de selección + _objectManager.UpdateSelectionVisuals(); + + if (DataContext is MainViewModel viewModel) + { + viewModel.HasUnsavedChanges = true; } } @@ -377,6 +424,7 @@ namespace CtrEditor if ((e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo || e.Source is UserControl) && DataContext is MainViewModel viewModel) { + ImagenEnTrabajoCanvas.Focus(); // Asegurar que el canvas tiene el foco e.Handled = true; ShowContextMenu(e.GetPosition(ImagenEnTrabajoCanvas)); } @@ -440,6 +488,63 @@ namespace CtrEditor contextMenu.IsOpen = true; } } + + private void Canvas_KeyDown(object sender, KeyEventArgs e) + { + HandleKeyDown(e); + } + + private void ScrollViewer_PreviewKeyDown(object sender, KeyEventArgs e) + { + // Prevenir que el ScrollViewer maneje las teclas de flecha + if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Up || e.Key == Key.Down) + { + HandleKeyDown(e); + e.Handled = true; + } + } + + private void HandleKeyDown(KeyEventArgs e) + { + if (DataContext is MainViewModel viewModel) + { + if (e.Key == Key.Delete) + { + viewModel.EliminarObjetoSeleccionado(); + e.Handled = true; + } + else if (e.Key == Key.Escape) + { + viewModel.SelectedItemOsList = null; + _objectManager.ClearSelection(); + _objectManager.RemoveResizeRectangles(); + e.Handled = true; + } + else if (_objectManager.SelectedObjects.Any()) + { + const float moveDistance = 0.01f; + switch (e.Key) + { + case Key.Left: + MoveSelectedObjects(-moveDistance, 0); + e.Handled = true; + break; + case Key.Right: + MoveSelectedObjects(moveDistance, 0); + e.Handled = true; + break; + case Key.Up: + MoveSelectedObjects(0, -moveDistance); + e.Handled = true; + break; + case Key.Down: + MoveSelectedObjects(0, moveDistance); + e.Handled = true; + break; + } + } + } + } } public class FloatValidationRule : ValidationRule diff --git a/ObjectAlignment.cs b/ObjectAlignment.cs index e42791a..7a8b25e 100644 --- a/ObjectAlignment.cs +++ b/ObjectAlignment.cs @@ -83,31 +83,27 @@ namespace CtrEditor { if (_selectedObjects.Count <= 2) return; - // Ordenar objetos por su centro X real (considerando rotación) var objectsWithCenters = _selectedObjects .Select(obj => new { Object = obj, - Center = GetObjectCenter(obj) + Center = GetObjectCenter(obj), + Dimensions = GetEffectiveDimensions(obj) }) .OrderBy(x => x.Center.X) .ToList(); - // Calcular el espacio total y el espaciado float leftMost = (float)objectsWithCenters.First().Center.X; float rightMost = (float)objectsWithCenters.Last().Center.X; - float totalWidth = rightMost - leftMost; - float spacing = totalWidth / (_selectedObjects.Count - 1); + float totalDistance = rightMost - leftMost; + float spacing = totalDistance / (_selectedObjects.Count - 1); - // Distribuir objetos basados en sus centros for (int i = 1; i < objectsWithCenters.Count - 1; i++) { - var obj = objectsWithCenters[i].Object; - var targetCenterX = leftMost + (spacing * i); - var currentCenter = GetObjectCenter(obj); - var deltaX = targetCenterX - currentCenter.X; - - obj.Left += (float)deltaX; + var obj = objectsWithCenters[i]; + var targetX = leftMost + (spacing * i); + float deltaX = (float)(targetX - obj.Center.X); + obj.Object.Left += deltaX; } } @@ -115,31 +111,27 @@ namespace CtrEditor { if (_selectedObjects.Count <= 2) return; - // Ordenar objetos por su centro Y real (considerando rotación) var objectsWithCenters = _selectedObjects .Select(obj => new { Object = obj, - Center = GetObjectCenter(obj) + Center = GetObjectCenter(obj), + Dimensions = GetEffectiveDimensions(obj) }) .OrderBy(x => x.Center.Y) .ToList(); - // Calcular el espacio total y el espaciado float topMost = (float)objectsWithCenters.First().Center.Y; float bottomMost = (float)objectsWithCenters.Last().Center.Y; - float totalHeight = bottomMost - topMost; - float spacing = totalHeight / (_selectedObjects.Count - 1); + float totalDistance = bottomMost - topMost; + float spacing = totalDistance / (_selectedObjects.Count - 1); - // Distribuir objetos basados en sus centros for (int i = 1; i < objectsWithCenters.Count - 1; i++) { - var obj = objectsWithCenters[i].Object; - var targetCenterY = topMost + (spacing * i); - var currentCenter = GetObjectCenter(obj); - var deltaY = targetCenterY - currentCenter.Y; - - obj.Top += (float)deltaY; + var obj = objectsWithCenters[i]; + var targetY = topMost + (spacing * i); + float deltaY = (float)(targetY - obj.Center.Y); + obj.Object.Top += deltaY; } } @@ -147,10 +139,11 @@ namespace CtrEditor { if (_selectedObjects.Count <= 1) return; - float averageWidth = _selectedObjects.Average(obj => obj.Ancho); + float averageWidth = _selectedObjects.Average(obj => GetEffectiveDimensions(obj).Width); foreach (var obj in _selectedObjects) { - obj.Ancho = averageWidth; + var currentDims = GetEffectiveDimensions(obj); + SetEffectiveDimensions(obj, averageWidth, currentDims.Height); } } @@ -158,10 +151,11 @@ namespace CtrEditor { if (_selectedObjects.Count <= 1) return; - float averageHeight = _selectedObjects.Average(obj => obj.Alto); + float averageHeight = _selectedObjects.Average(obj => GetEffectiveDimensions(obj).Height); foreach (var obj in _selectedObjects) { - obj.Alto = averageHeight; + var currentDims = GetEffectiveDimensions(obj); + SetEffectiveDimensions(obj, currentDims.Width, averageHeight); } } @@ -181,14 +175,21 @@ namespace CtrEditor if (_selectedObjects.Count <= 1) return; var sortedObjects = _selectedObjects - .OrderBy(obj => obj.Left) + .OrderBy(obj => GetObjectCenter(obj).X) .ToList(); for (int i = 1; i < sortedObjects.Count; i++) { var previousObj = sortedObjects[i - 1]; var currentObj = sortedObjects[i]; - currentObj.Left = previousObj.Left + previousObj.Ancho; + var previousCenter = GetObjectCenter(previousObj); + var currentCenter = GetObjectCenter(currentObj); + var previousDims = GetEffectiveDimensions(previousObj); + + float offset = previousDims.Width / 2; + float newX = (float)(previousCenter.X + offset); + float deltaX = (float)(newX - (currentCenter.X - GetEffectiveDimensions(currentObj).Width / 2)); + currentObj.Left += deltaX; } } @@ -197,14 +198,21 @@ namespace CtrEditor if (_selectedObjects.Count <= 1) return; var sortedObjects = _selectedObjects - .OrderBy(obj => obj.Top) + .OrderBy(obj => GetObjectCenter(obj).Y) .ToList(); for (int i = 1; i < sortedObjects.Count; i++) { var previousObj = sortedObjects[i - 1]; var currentObj = sortedObjects[i]; - currentObj.Top = previousObj.Top + previousObj.Alto; + var previousCenter = GetObjectCenter(previousObj); + var currentCenter = GetObjectCenter(currentObj); + var previousDims = GetEffectiveDimensions(previousObj); + + float offset = previousDims.Height / 2; + float newY = (float)(previousCenter.Y + offset); + float deltaY = (float)(newY - (currentCenter.Y - GetEffectiveDimensions(currentObj).Height / 2)); + currentObj.Top += deltaY; } } @@ -214,10 +222,8 @@ namespace CtrEditor float centerX = obj.Left + (obj.Ancho / 2); float centerY = obj.Top + (obj.Alto / 2); - // Si el objeto está rotado, calcular el centro real if (obj.Angulo != 0) { - // Obtener el centro después de la rotación var rotatedX = obj.Left + (Math.Cos(angleRad) * obj.Ancho / 2 - Math.Sin(angleRad) * obj.Alto / 2); var rotatedY = obj.Top + (Math.Sin(angleRad) * obj.Ancho / 2 + Math.Cos(angleRad) * obj.Alto / 2); @@ -226,5 +232,35 @@ namespace CtrEditor return new Point(centerX, centerY); } + + private bool IsObjectVertical(osBase obj) + { + double normalizedAngle = obj.Angulo % 180; + if (normalizedAngle < 0) normalizedAngle += 180; + return normalizedAngle >= 45 && normalizedAngle < 135; + } + + private (float Width, float Height) GetEffectiveDimensions(osBase obj) + { + if (IsObjectVertical(obj)) + { + return (obj.Alto, obj.Ancho); + } + return (obj.Ancho, obj.Alto); + } + + private void SetEffectiveDimensions(osBase obj, float width, float height) + { + if (IsObjectVertical(obj)) + { + obj.Alto = width; + obj.Ancho = height; + } + else + { + obj.Ancho = width; + obj.Alto = height; + } + } } } diff --git a/ObjectManipulationManager.cs b/ObjectManipulationManager.cs index d549a4d..0c9ef80 100644 --- a/ObjectManipulationManager.cs +++ b/ObjectManipulationManager.cs @@ -87,10 +87,14 @@ namespace CtrEditor public void UpdateSelectionVisuals() { + // Asegurarse de que el canvas haya actualizado su layout + _canvas.UpdateLayout(); + RemoveResizeRectangles(); if (_selectedObjects.Any()) { AddResizeRectangles(_selectedObjects); + UpdateSelectionHighlights(); } }