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()
{
var deletedObjects = _selectedObjects.Where(obj =>
obj.VisualRepresentation == null ||
var deletedObjects = _selectedObjects.Where(obj =>
obj.VisualRepresentation == null ||
!_canvas.Children.Contains(obj.VisualRepresentation)).ToList();
foreach (var obj in deletedObjects)
@ -202,7 +202,7 @@ namespace CtrEditor
PurgeDeletedObjects();
// Asegurarse de que el canvas haya actualizado su layout
_canvas.UpdateLayout();
RemoveResizeRectangles();
if (_selectedObjects.Any())
{
@ -253,14 +253,15 @@ namespace CtrEditor
public void AddResizeRectangles(IEnumerable<osBase> selectedObjects)
{
double rectHighlightSize = 1;
RemoveResizeRectangles();
RemoveResizeRectangles();
// Verificar si hay objetos bloqueados
bool hasLockedObjects = selectedObjects.Any(obj => obj.Lock_movement);
// Calcular el bounding box que contenga todos los objetos seleccionados
Rect boundingBox = CalculateTotalBoundingBox(selectedObjects);
if (_selectedObjectsAreVisible) {
if (_selectedObjectsAreVisible)
{
FuncionesBase.MutableRect rectBox = new FuncionesBase.MutableRect(boundingBox);
rectBox.Left -= (float)rectHighlightSize;
@ -303,7 +304,7 @@ namespace CtrEditor
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
Rect objectBounds = VisualTreeHelper.GetDescendantBounds(obj.VisualRepresentation);
@ -336,7 +337,7 @@ namespace CtrEditor
// Cambiar el estilo visual dependiendo si hay objetos bloqueados
Brush strokeBrush;
DoubleCollection dashArray;
if (hasLockedObjects)
{
// 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
double minObjectDimension = Math.Min(rectBox.Width, rectBox.Height);
double rectSize = Math.Min(defaultRectSize, minObjectDimension / 3);
// Asegurar un tamaño mínimo para los manejadores
rectSize = Math.Max(rectSize, 6);
// Calcular el offset para posicionar los manejadores fuera del rectángulo
double offset = rectSize / 2;
@ -419,9 +420,9 @@ namespace CtrEditor
return (Cursors.SizeWE, Cursors.SizeNS, Cursors.SizeNWSE);
double angle = Math.Abs(firstObject.Angulo % 360);
// 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))
{
return (Cursors.SizeWE, Cursors.SizeNS, Cursors.SizeNWSE);
@ -569,7 +570,7 @@ namespace CtrEditor
}
UpdateSelectionVisuals();
// Update the view model's selection state
vm.NotifySelectionChanged();
}
@ -583,7 +584,7 @@ namespace CtrEditor
_selectedObjects.Remove(obj);
obj.IsSelected = false;
RemoveSelectionHighlight(obj.VisualRepresentation);
// Update the view model's selection state
if (_mainWindow.DataContext is MainViewModel vm)
{
@ -652,7 +653,7 @@ namespace CtrEditor
Width = transformedBoundingBox.Width,
Height = transformedBoundingBox.Height,
Fill = Brushes.Transparent,
Stroke = new SolidColorBrush(isReference ?
Stroke = new SolidColorBrush(isReference ?
Color.FromArgb(180, 128, 0, 128) : // Purple for reference
Color.FromArgb(180, 255, 0, 0)), // Red for others
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
bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (_resizeRectangles != null && _resizeRectangles.Contains(sender))
{
// Si hay objetos bloqueados, no permitir redimensionamiento
@ -724,10 +725,10 @@ namespace CtrEditor
e.Handled = true;
return;
}
// Capturar estado antes de iniciar redimensionamiento
CaptureUndoState();
_currentDraggingRectangle = sender as Rectangle;
_lastMousePosition = e.GetPosition(_canvas);
_currentDraggingRectangle.CaptureMouse();
@ -741,10 +742,10 @@ namespace CtrEditor
if (userControl != null && userControl.DataContext is osBase datos)
{
bool isControlPressed = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
// Determinar qué objetos serán afectados por el movimiento
List<osBase> objectsToMove = new List<osBase>();
if (!isControlPressed)
{
// 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
objectsToMove.Add(datos);
}
// Verificar si alguno de los objetos a mover está bloqueado
bool willMoveLockedObjects = objectsToMove.Any(obj => obj.Lock_movement);
if (!willMoveLockedObjects)
{
// Capturar estado antes de iniciar movimiento
CaptureUndoStateForObjects(objectsToMove);
userControl.CaptureMouse();
_currentDraggingControl = userControl;
_isMovingUserControl = true;
InitializeDrag(e);
}
}
// Manejar la selección después de capturar el estado
HandleObjectSelection(userControl, datos);
// Actualizar el estado de objetos bloqueados después de la selección
hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (hasLockedObjects && !isControlPressed)
{
// Si hay objetos bloqueados, no permitir el inicio del arrastre
@ -831,14 +832,14 @@ namespace CtrEditor
private void HandleDrag(Point currentPosition)
{
PurgeDeletedObjects();
// Verificar si hay objetos bloqueados antes de mover
bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (hasLockedObjects)
{
return; // No mover si hay objetos bloqueados
}
var dx = currentPosition.X - _startPointUserControl.X;
var dy = currentPosition.Y - _startPointUserControl.Y;
@ -992,11 +993,11 @@ namespace CtrEditor
return HandleMode.None;
double angle = Math.Abs(firstObject.Angulo % 360);
// Si el objeto no está significativamente rotado, usar el comportamiento por defecto
if (angle < 15 || (angle > 345 && angle < 360) ||
(angle > 75 && angle < 105) ||
(angle > 165 && angle < 195) ||
if (angle < 15 || (angle > 345 && angle < 360) ||
(angle > 75 && angle < 105) ||
(angle > 165 && angle < 195) ||
(angle > 255 && angle < 285))
{
return DetermineHandleModeDefault(resizeDirection);
@ -1038,14 +1039,14 @@ namespace CtrEditor
private void HandleResize(Point currentPosition, HandleMode mode)
{
PurgeDeletedObjects();
// Verificar si hay objetos bloqueados antes de redimensionar
bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (hasLockedObjects)
{
return; // No redimensionar si hay objetos bloqueados
}
RemoveAllSelectionHighlights(); // Remover antes de redimensionar
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
// Convertir ángulo de grados a radianes
double angleRad = obj.Angulo * Math.PI / 180.0;
// Calcular los componentes de cambio transformados según la rotación
// Rotar el vector de cambio por el ángulo negativo del objeto para obtener
// los cambios en el sistema de coordenadas local del objeto
double cos = Math.Cos(-angleRad);
double sin = Math.Sin(-angleRad);
double localDeltaX = deltaX * cos - deltaY * sin;
double localDeltaY = deltaX * sin + deltaY * cos;
@ -1115,16 +1116,19 @@ namespace CtrEditor
private void HandleRotation(Point currentPosition)
{
PurgeDeletedObjects();
// Verificar si hay objetos bloqueados antes de rotar
bool hasLockedObjects = _selectedObjects.Any(obj => obj.Lock_movement);
if (hasLockedObjects)
{
return; // No rotar si hay objetos bloqueados
}
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
double deltaX = currentPosition.X - _transformedBoundingBoxCenter.X;
double deltaY = currentPosition.Y - _transformedBoundingBoxCenter.Y;
@ -1137,11 +1141,48 @@ namespace CtrEditor
else
{
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();
@ -1237,10 +1278,10 @@ namespace CtrEditor
ClearSelection();
RemoveResizeRectangles();
RemoveAllSelectionHighlights();
// Ensure the property panel is cleared by explicitly setting SelectedItemOsList to null
viewModel.SelectedItemOsList = null;
// Actualizar el estado de cambios sin guardar
if (viewModel != null)
{
@ -1339,7 +1380,7 @@ namespace CtrEditor
{
// Capturar solo el estado de los objetos seleccionados
var undoState = new UndoState(_selectedObjects);
// Mantener solo los últimos MaxUndoSteps estados
if (_undoHistory.Count >= MaxUndoSteps)
{
@ -1353,7 +1394,7 @@ namespace CtrEditor
_undoHistory.Push(state);
}
}
_undoHistory.Push(undoState);
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
var undoState = new UndoState(objectsList);
// Mantener solo los últimos MaxUndoSteps estados
if (_undoHistory.Count >= MaxUndoSteps)
{
@ -1388,7 +1429,7 @@ namespace CtrEditor
_undoHistory.Push(state);
}
}
_undoHistory.Push(undoState);
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)
{
_isApplyingUndo = true;
try
{
var undoState = _undoHistory.Pop();
@ -1443,10 +1484,10 @@ namespace CtrEditor
// Actualizar los visuales de selección
UpdateSelectionVisuals();
// Marcar como cambios sin guardar
viewModel.HasUnsavedChanges = true;
Console.WriteLine("Undo aplicado exitosamente");
}
finally