Se realizaron mejoras en la gestión de objetos visuales en la clase ObjectManipulationManager. Se optimizó la lógica para purgar objetos eliminados y se mejoró la rotación de objetos, permitiendo rotaciones en incrementos de 45 grados al mantener presionada la tecla Shift. Además, se ajustaron espacios en blanco y se mejoró la legibilidad del código en varias secciones.

This commit is contained in:
Miguel 2025-06-23 21:36:53 +02:00
parent 75c507be4e
commit ac8773ebc7
1 changed files with 90 additions and 49 deletions

View File

@ -173,8 +173,8 @@ namespace CtrEditor
private void PurgeDeletedObjects() private void PurgeDeletedObjects()
{ {
var deletedObjects = _selectedObjects.Where(obj => var deletedObjects = _selectedObjects.Where(obj =>
obj.VisualRepresentation == null || obj.VisualRepresentation == null ||
!_canvas.Children.Contains(obj.VisualRepresentation)).ToList(); !_canvas.Children.Contains(obj.VisualRepresentation)).ToList();
foreach (var obj in deletedObjects) foreach (var obj in deletedObjects)
@ -202,7 +202,7 @@ namespace CtrEditor
PurgeDeletedObjects(); PurgeDeletedObjects();
// Asegurarse de que el canvas haya actualizado su layout // Asegurarse de que el canvas haya actualizado su layout
_canvas.UpdateLayout(); _canvas.UpdateLayout();
RemoveResizeRectangles(); RemoveResizeRectangles();
if (_selectedObjects.Any()) if (_selectedObjects.Any())
{ {
@ -253,14 +253,15 @@ namespace CtrEditor
public void AddResizeRectangles(IEnumerable<osBase> selectedObjects) public void AddResizeRectangles(IEnumerable<osBase> selectedObjects)
{ {
double rectHighlightSize = 1; double rectHighlightSize = 1;
RemoveResizeRectangles(); RemoveResizeRectangles();
// Verificar si hay objetos bloqueados // Verificar si hay objetos bloqueados
bool hasLockedObjects = selectedObjects.Any(obj => obj.Lock_movement); bool hasLockedObjects = selectedObjects.Any(obj => obj.Lock_movement);
// Calcular el bounding box que contenga todos los objetos seleccionados // Calcular el bounding box que contenga todos los objetos seleccionados
Rect boundingBox = CalculateTotalBoundingBox(selectedObjects); Rect boundingBox = CalculateTotalBoundingBox(selectedObjects);
if (_selectedObjectsAreVisible) { if (_selectedObjectsAreVisible)
{
FuncionesBase.MutableRect rectBox = new FuncionesBase.MutableRect(boundingBox); FuncionesBase.MutableRect rectBox = new FuncionesBase.MutableRect(boundingBox);
rectBox.Left -= (float)rectHighlightSize; rectBox.Left -= (float)rectHighlightSize;
@ -303,7 +304,7 @@ namespace CtrEditor
foreach (var obj in selectedObjects) foreach (var obj in selectedObjects)
{ {
if (obj.VisualRepresentation != null && obj.VisualRepresentation.Visibility!=Visibility.Collapsed) if (obj.VisualRepresentation != null && obj.VisualRepresentation.Visibility != Visibility.Collapsed)
{ {
// Obtener el bounding box del objeto actual // Obtener el bounding box del objeto actual
Rect objectBounds = VisualTreeHelper.GetDescendantBounds(obj.VisualRepresentation); Rect objectBounds = VisualTreeHelper.GetDescendantBounds(obj.VisualRepresentation);
@ -336,7 +337,7 @@ namespace CtrEditor
// Cambiar el estilo visual dependiendo si hay objetos bloqueados // Cambiar el estilo visual dependiendo si hay objetos bloqueados
Brush strokeBrush; Brush strokeBrush;
DoubleCollection dashArray; DoubleCollection dashArray;
if (hasLockedObjects) if (hasLockedObjects)
{ {
// Estilo para objetos bloqueados (rojo/naranja con líneas más separadas) // Estilo para objetos bloqueados (rojo/naranja con líneas más separadas)
@ -377,10 +378,10 @@ namespace CtrEditor
// Calcular el tamaño apropiado para los manejadores basado en el tamaño del objeto // Calcular el tamaño apropiado para los manejadores basado en el tamaño del objeto
double minObjectDimension = Math.Min(rectBox.Width, rectBox.Height); double minObjectDimension = Math.Min(rectBox.Width, rectBox.Height);
double rectSize = Math.Min(defaultRectSize, minObjectDimension / 3); double rectSize = Math.Min(defaultRectSize, minObjectDimension / 3);
// Asegurar un tamaño mínimo para los manejadores // Asegurar un tamaño mínimo para los manejadores
rectSize = Math.Max(rectSize, 6); rectSize = Math.Max(rectSize, 6);
// Calcular el offset para posicionar los manejadores fuera del rectángulo // Calcular el offset para posicionar los manejadores fuera del rectángulo
double offset = rectSize / 2; double offset = rectSize / 2;
@ -419,9 +420,9 @@ namespace CtrEditor
return (Cursors.SizeWE, Cursors.SizeNS, Cursors.SizeNWSE); return (Cursors.SizeWE, Cursors.SizeNS, Cursors.SizeNWSE);
double angle = Math.Abs(firstObject.Angulo % 360); double angle = Math.Abs(firstObject.Angulo % 360);
// Si el objeto no está significativamente rotado, usar cursores estándar // Si el objeto no está significativamente rotado, usar cursores estándar
if (angle < 15 || (angle > 345 && angle < 360) || if (angle < 15 || (angle > 345 && angle < 360) ||
(angle > 165 && angle < 195)) (angle > 165 && angle < 195))
{ {
return (Cursors.SizeWE, Cursors.SizeNS, Cursors.SizeNWSE); return (Cursors.SizeWE, Cursors.SizeNS, Cursors.SizeNWSE);
@ -569,7 +570,7 @@ namespace CtrEditor
} }
UpdateSelectionVisuals(); UpdateSelectionVisuals();
// Update the view model's selection state // Update the view model's selection state
vm.NotifySelectionChanged(); vm.NotifySelectionChanged();
} }
@ -583,7 +584,7 @@ namespace CtrEditor
_selectedObjects.Remove(obj); _selectedObjects.Remove(obj);
obj.IsSelected = false; obj.IsSelected = false;
RemoveSelectionHighlight(obj.VisualRepresentation); RemoveSelectionHighlight(obj.VisualRepresentation);
// Update the view model's selection state // Update the view model's selection state
if (_mainWindow.DataContext is MainViewModel vm) if (_mainWindow.DataContext is MainViewModel vm)
{ {
@ -652,7 +653,7 @@ namespace CtrEditor
Width = transformedBoundingBox.Width, Width = transformedBoundingBox.Width,
Height = transformedBoundingBox.Height, Height = transformedBoundingBox.Height,
Fill = Brushes.Transparent, Fill = Brushes.Transparent,
Stroke = new SolidColorBrush(isReference ? Stroke = new SolidColorBrush(isReference ?
Color.FromArgb(180, 128, 0, 128) : // Purple for reference Color.FromArgb(180, 128, 0, 128) : // Purple for reference
Color.FromArgb(180, 255, 0, 0)), // Red for others Color.FromArgb(180, 255, 0, 0)), // Red for others
StrokeThickness = isReference ? 3 : 2, // Más grueso para el de referencia StrokeThickness = isReference ? 3 : 2, // Más grueso para el de referencia
@ -715,7 +716,7 @@ namespace CtrEditor
{ {
// Verificar si hay objetos bloqueados en la selección actual // Verificar si hay objetos bloqueados en la selección actual
bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement); bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (_resizeRectangles != null && _resizeRectangles.Contains(sender)) if (_resizeRectangles != null && _resizeRectangles.Contains(sender))
{ {
// Si hay objetos bloqueados, no permitir redimensionamiento // Si hay objetos bloqueados, no permitir redimensionamiento
@ -724,10 +725,10 @@ namespace CtrEditor
e.Handled = true; e.Handled = true;
return; return;
} }
// Capturar estado antes de iniciar redimensionamiento // Capturar estado antes de iniciar redimensionamiento
CaptureUndoState(); CaptureUndoState();
_currentDraggingRectangle = sender as Rectangle; _currentDraggingRectangle = sender as Rectangle;
_lastMousePosition = e.GetPosition(_canvas); _lastMousePosition = e.GetPosition(_canvas);
_currentDraggingRectangle.CaptureMouse(); _currentDraggingRectangle.CaptureMouse();
@ -741,10 +742,10 @@ namespace CtrEditor
if (userControl != null && userControl.DataContext is osBase datos) if (userControl != null && userControl.DataContext is osBase datos)
{ {
bool isControlPressed = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl); bool isControlPressed = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
// Determinar qué objetos serán afectados por el movimiento // Determinar qué objetos serán afectados por el movimiento
List<osBase> objectsToMove = new List<osBase>(); List<osBase> objectsToMove = new List<osBase>();
if (!isControlPressed) if (!isControlPressed)
{ {
// Si no está Ctrl presionado y vamos a hacer dragging // Si no está Ctrl presionado y vamos a hacer dragging
@ -758,28 +759,28 @@ namespace CtrEditor
// Si no está seleccionado, solo vamos a mover este objeto // Si no está seleccionado, solo vamos a mover este objeto
objectsToMove.Add(datos); objectsToMove.Add(datos);
} }
// Verificar si alguno de los objetos a mover está bloqueado // Verificar si alguno de los objetos a mover está bloqueado
bool willMoveLockedObjects = objectsToMove.Any(obj => obj.Lock_movement); bool willMoveLockedObjects = objectsToMove.Any(obj => obj.Lock_movement);
if (!willMoveLockedObjects) if (!willMoveLockedObjects)
{ {
// Capturar estado antes de iniciar movimiento // Capturar estado antes de iniciar movimiento
CaptureUndoStateForObjects(objectsToMove); CaptureUndoStateForObjects(objectsToMove);
userControl.CaptureMouse(); userControl.CaptureMouse();
_currentDraggingControl = userControl; _currentDraggingControl = userControl;
_isMovingUserControl = true; _isMovingUserControl = true;
InitializeDrag(e); InitializeDrag(e);
} }
} }
// Manejar la selección después de capturar el estado // Manejar la selección después de capturar el estado
HandleObjectSelection(userControl, datos); HandleObjectSelection(userControl, datos);
// Actualizar el estado de objetos bloqueados después de la selección // Actualizar el estado de objetos bloqueados después de la selección
hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement); hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (hasLockedObjects && !isControlPressed) if (hasLockedObjects && !isControlPressed)
{ {
// Si hay objetos bloqueados, no permitir el inicio del arrastre // Si hay objetos bloqueados, no permitir el inicio del arrastre
@ -831,14 +832,14 @@ namespace CtrEditor
private void HandleDrag(Point currentPosition) private void HandleDrag(Point currentPosition)
{ {
PurgeDeletedObjects(); PurgeDeletedObjects();
// Verificar si hay objetos bloqueados antes de mover // Verificar si hay objetos bloqueados antes de mover
bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement); bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (hasLockedObjects) if (hasLockedObjects)
{ {
return; // No mover si hay objetos bloqueados return; // No mover si hay objetos bloqueados
} }
var dx = currentPosition.X - _startPointUserControl.X; var dx = currentPosition.X - _startPointUserControl.X;
var dy = currentPosition.Y - _startPointUserControl.Y; var dy = currentPosition.Y - _startPointUserControl.Y;
@ -992,11 +993,11 @@ namespace CtrEditor
return HandleMode.None; return HandleMode.None;
double angle = Math.Abs(firstObject.Angulo % 360); double angle = Math.Abs(firstObject.Angulo % 360);
// Si el objeto no está significativamente rotado, usar el comportamiento por defecto // Si el objeto no está significativamente rotado, usar el comportamiento por defecto
if (angle < 15 || (angle > 345 && angle < 360) || if (angle < 15 || (angle > 345 && angle < 360) ||
(angle > 75 && angle < 105) || (angle > 75 && angle < 105) ||
(angle > 165 && angle < 195) || (angle > 165 && angle < 195) ||
(angle > 255 && angle < 285)) (angle > 255 && angle < 285))
{ {
return DetermineHandleModeDefault(resizeDirection); return DetermineHandleModeDefault(resizeDirection);
@ -1038,14 +1039,14 @@ namespace CtrEditor
private void HandleResize(Point currentPosition, HandleMode mode) private void HandleResize(Point currentPosition, HandleMode mode)
{ {
PurgeDeletedObjects(); PurgeDeletedObjects();
// Verificar si hay objetos bloqueados antes de redimensionar // Verificar si hay objetos bloqueados antes de redimensionar
bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement); bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (hasLockedObjects) if (hasLockedObjects)
{ {
return; // No redimensionar si hay objetos bloqueados return; // No redimensionar si hay objetos bloqueados
} }
RemoveAllSelectionHighlights(); // Remover antes de redimensionar RemoveAllSelectionHighlights(); // Remover antes de redimensionar
foreach (var selectedObject in _selectedObjects) foreach (var selectedObject in _selectedObjects)
@ -1080,13 +1081,13 @@ namespace CtrEditor
// Para objetos rotados, transformar los cambios del mouse según la orientación del objeto // Para objetos rotados, transformar los cambios del mouse según la orientación del objeto
// Convertir ángulo de grados a radianes // Convertir ángulo de grados a radianes
double angleRad = obj.Angulo * Math.PI / 180.0; double angleRad = obj.Angulo * Math.PI / 180.0;
// Calcular los componentes de cambio transformados según la rotación // Calcular los componentes de cambio transformados según la rotación
// Rotar el vector de cambio por el ángulo negativo del objeto para obtener // Rotar el vector de cambio por el ángulo negativo del objeto para obtener
// los cambios en el sistema de coordenadas local del objeto // los cambios en el sistema de coordenadas local del objeto
double cos = Math.Cos(-angleRad); double cos = Math.Cos(-angleRad);
double sin = Math.Sin(-angleRad); double sin = Math.Sin(-angleRad);
double localDeltaX = deltaX * cos - deltaY * sin; double localDeltaX = deltaX * cos - deltaY * sin;
double localDeltaY = deltaX * sin + deltaY * cos; double localDeltaY = deltaX * sin + deltaY * cos;
@ -1115,16 +1116,19 @@ namespace CtrEditor
private void HandleRotation(Point currentPosition) private void HandleRotation(Point currentPosition)
{ {
PurgeDeletedObjects(); PurgeDeletedObjects();
// Verificar si hay objetos bloqueados antes de rotar // Verificar si hay objetos bloqueados antes de rotar
bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement); bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (hasLockedObjects) if (hasLockedObjects)
{ {
return; // No rotar si hay objetos bloqueados return; // No rotar si hay objetos bloqueados
} }
RemoveAllSelectionHighlights(); // Remover antes de rotar RemoveAllSelectionHighlights(); // Remover antes de rotar
// Verificar si la tecla Shift está presionada para rotación en incrementos de 45 grados
bool isShiftPressed = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
// Calcular el ángulo respecto al centro del bounding box que contiene todos los objetos seleccionados // Calcular el ángulo respecto al centro del bounding box que contiene todos los objetos seleccionados
double deltaX = currentPosition.X - _transformedBoundingBoxCenter.X; double deltaX = currentPosition.X - _transformedBoundingBoxCenter.X;
double deltaY = currentPosition.Y - _transformedBoundingBoxCenter.Y; double deltaY = currentPosition.Y - _transformedBoundingBoxCenter.Y;
@ -1137,11 +1141,48 @@ namespace CtrEditor
else else
{ {
double deltaAngle = angle - _lastAngle; double deltaAngle = angle - _lastAngle;
foreach (var selectedObject in _selectedObjects)
if (isShiftPressed)
{ {
selectedObject.Rotate(deltaAngle); // Rotación en incrementos de 45 grados
// Calcular el ángulo total acumulado desde el inicio de la rotación
double totalAngleChange = angle - _lastAngle;
// Determinar a qué incremento de 45 grados corresponde
double snapAngle = Math.Round(totalAngleChange / 45.0) * 45.0;
// Solo aplicar la rotación si hay un cambio significativo (al menos 22.5 grados de movimiento)
if (Math.Abs(totalAngleChange) > 22.5)
{
// Calcular el cambio real que necesitamos aplicar
double actualRotationChange = snapAngle;
foreach (var selectedObject in _selectedObjects)
{
// Obtener el ángulo actual del objeto
double currentObjectAngle = selectedObject.Angulo;
// Calcular el nuevo ángulo alineado a incrementos de 45 grados
double targetAngle = Math.Round((currentObjectAngle + actualRotationChange) / 45.0) * 45.0;
// Aplicar la rotación necesaria para llegar al ángulo objetivo
double rotationNeeded = targetAngle - currentObjectAngle;
selectedObject.Rotate(rotationNeeded);
}
// Actualizar el ángulo de referencia para evitar aplicar la misma rotación múltiples veces
_lastAngle = (float)angle;
}
}
else
{
// Rotación libre (comportamiento original)
foreach (var selectedObject in _selectedObjects)
{
selectedObject.Rotate(deltaAngle);
}
_lastAngle = (float)angle;
} }
_lastAngle = (float)angle;
} }
UpdateAllSelectionHighlights(); UpdateAllSelectionHighlights();
@ -1237,10 +1278,10 @@ namespace CtrEditor
ClearSelection(); ClearSelection();
RemoveResizeRectangles(); RemoveResizeRectangles();
RemoveAllSelectionHighlights(); RemoveAllSelectionHighlights();
// Ensure the property panel is cleared by explicitly setting SelectedItemOsList to null // Ensure the property panel is cleared by explicitly setting SelectedItemOsList to null
viewModel.SelectedItemOsList = null; viewModel.SelectedItemOsList = null;
// Actualizar el estado de cambios sin guardar // Actualizar el estado de cambios sin guardar
if (viewModel != null) if (viewModel != null)
{ {
@ -1339,7 +1380,7 @@ namespace CtrEditor
{ {
// Capturar solo el estado de los objetos seleccionados // Capturar solo el estado de los objetos seleccionados
var undoState = new UndoState(_selectedObjects); var undoState = new UndoState(_selectedObjects);
// Mantener solo los últimos MaxUndoSteps estados // Mantener solo los últimos MaxUndoSteps estados
if (_undoHistory.Count >= MaxUndoSteps) if (_undoHistory.Count >= MaxUndoSteps)
{ {
@ -1353,7 +1394,7 @@ namespace CtrEditor
_undoHistory.Push(state); _undoHistory.Push(state);
} }
} }
_undoHistory.Push(undoState); _undoHistory.Push(undoState);
Console.WriteLine($"Estado capturado para undo de {_selectedObjects.Count} objetos. Historial: {_undoHistory.Count} estados"); Console.WriteLine($"Estado capturado para undo de {_selectedObjects.Count} objetos. Historial: {_undoHistory.Count} estados");
} }
@ -1374,7 +1415,7 @@ namespace CtrEditor
{ {
// Capturar solo el estado de los objetos especificados // Capturar solo el estado de los objetos especificados
var undoState = new UndoState(objectsList); var undoState = new UndoState(objectsList);
// Mantener solo los últimos MaxUndoSteps estados // Mantener solo los últimos MaxUndoSteps estados
if (_undoHistory.Count >= MaxUndoSteps) if (_undoHistory.Count >= MaxUndoSteps)
{ {
@ -1388,7 +1429,7 @@ namespace CtrEditor
_undoHistory.Push(state); _undoHistory.Push(state);
} }
} }
_undoHistory.Push(undoState); _undoHistory.Push(undoState);
Console.WriteLine($"Estado capturado para undo de {objectsList.Count} objetos específicos. Historial: {_undoHistory.Count} estados"); Console.WriteLine($"Estado capturado para undo de {objectsList.Count} objetos específicos. Historial: {_undoHistory.Count} estados");
} }
@ -1417,7 +1458,7 @@ namespace CtrEditor
if (_mainWindow.DataContext is MainViewModel viewModel) if (_mainWindow.DataContext is MainViewModel viewModel)
{ {
_isApplyingUndo = true; _isApplyingUndo = true;
try try
{ {
var undoState = _undoHistory.Pop(); var undoState = _undoHistory.Pop();
@ -1443,10 +1484,10 @@ namespace CtrEditor
// Actualizar los visuales de selección // Actualizar los visuales de selección
UpdateSelectionVisuals(); UpdateSelectionVisuals();
// Marcar como cambios sin guardar // Marcar como cambios sin guardar
viewModel.HasUnsavedChanges = true; viewModel.HasUnsavedChanges = true;
Console.WriteLine("Undo aplicado exitosamente"); Console.WriteLine("Undo aplicado exitosamente");
} }
finally finally