Mejorado de panning y zoom

This commit is contained in:
Miguel 2025-02-18 21:52:27 +01:00
parent 67c6464ea1
commit 5ee91dd26a
3 changed files with 250 additions and 11 deletions

View File

@ -134,10 +134,12 @@ namespace CtrEditor
{ {
_isDraggingCanvas = false; _isDraggingCanvas = false;
ImagenEnTrabajoCanvas.ReleaseMouseCapture(); ImagenEnTrabajoCanvas.ReleaseMouseCapture();
Mouse.OverrideCursor = null;
if (DataContext is MainViewModel viewModel && viewModel.SelectedItemOsList != null) if (_objectManager.SelectedObjects.Count > 0)
{ {
_objectManager.MakeResizeRectanglesNormal(); _objectManager.MakeResizeRectanglesNormal();
_objectManager.UpdateSelectionVisuals(); // Agregar esta línea
} }
e.Handled = true; e.Handled = true;
} }
@ -147,12 +149,14 @@ namespace CtrEditor
{ {
if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas) if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas)
{ {
// Solo activar el panning si el clic fue directamente en el canvas // Solo permitir el panning si el clic fue en el canvas o en la imagen de fondo
if (e.Source == ImagenEnTrabajoCanvas) // y no en otros controles
if (e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo)
{ {
_isDraggingCanvas = true; _isDraggingCanvas = true;
_lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer); _lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
ImagenEnTrabajoCanvas.CaptureMouse(); ImagenEnTrabajoCanvas.CaptureMouse();
Mouse.OverrideCursor = Cursors.Hand;
if (DataContext is MainViewModel viewModel) if (DataContext is MainViewModel viewModel)
{ {
@ -224,9 +228,10 @@ namespace CtrEditor
RenderOptions.SetBitmapScalingMode(ImagenEnTrabajoCanvas, BitmapScalingMode.HighQuality); RenderOptions.SetBitmapScalingMode(ImagenEnTrabajoCanvas, BitmapScalingMode.HighQuality);
if (DataContext is MainViewModel viewModel && viewModel.SelectedItemOsList != null) if (_objectManager.SelectedObjects.Count > 0)
{ {
_objectManager.MakeResizeRectanglesNormal(); _objectManager.MakeResizeRectanglesNormal();
_objectManager.UpdateSelectionVisuals(); // Agregar esta línea
} }
return; return;
@ -298,8 +303,6 @@ namespace CtrEditor
_objectManager.ClearSelection(); _objectManager.ClearSelection();
_objectManager.RemoveResizeRectangles(); _objectManager.RemoveResizeRectangles();
// Desactivar el modo de selección múltiple
viewModel.IsMultiSelectionActive = false;
e.Handled = true; e.Handled = true;
} }
@ -373,9 +376,10 @@ namespace CtrEditor
private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e) private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{ {
// Aceptar el evento si viene del canvas o de la imagen de fondo // Aceptar el evento si viene del canvas o de la imagen de fondo
if ((e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo) && DataContext is MainViewModel viewModel) if ((e.Source == ImagenEnTrabajoCanvas || e.Source == imagenDeFondo || e.Source is UserControl) &&
DataContext is MainViewModel viewModel)
{ {
e.Handled = true; // Importante: marcar el evento como manejado e.Handled = true;
ShowContextMenu(e.GetPosition(ImagenEnTrabajoCanvas)); ShowContextMenu(e.GetPosition(ImagenEnTrabajoCanvas));
} }
} }
@ -387,7 +391,7 @@ namespace CtrEditor
{ {
Header = "Modo Multi-Selección", Header = "Modo Multi-Selección",
IsCheckable = true, IsCheckable = true,
StaysOpenOnClick = false // Cerrar el menú al hacer clic StaysOpenOnClick = false
}; };
if (DataContext is MainViewModel viewModel) if (DataContext is MainViewModel viewModel)
@ -397,6 +401,26 @@ namespace CtrEditor
{ {
viewModel.IsMultiSelectionActive = multiSelectMenuItem.IsChecked; viewModel.IsMultiSelectionActive = multiSelectMenuItem.IsChecked;
}; };
// Solo mostrar opciones de alineación si hay objetos seleccionados
if (_objectManager.SelectedObjects.Count > 1)
{
var alignmentMenu = new MenuItem { Header = "Alinear" };
alignmentMenu.Items.Add(new MenuItem { Header = "Alinear a la Izquierda", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.Left)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Alinear a la Derecha", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.Right)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Alinear Arriba", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.Top)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Alinear Abajo", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.Bottom)) });
alignmentMenu.Items.Add(new Separator());
alignmentMenu.Items.Add(new MenuItem { Header = "Centrar Horizontalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.CenterHorizontally)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Centrar Verticalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.CenterVertically)) });
alignmentMenu.Items.Add(new Separator());
alignmentMenu.Items.Add(new MenuItem { Header = "Distribuir Horizontalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.DistributeHorizontally)) });
alignmentMenu.Items.Add(new MenuItem { Header = "Distribuir Verticalmente", Command = new RelayCommand(() => _objectManager.AlignObjects(AlignmentType.DistributeVertically)) });
contextMenu.Items.Add(alignmentMenu);
contextMenu.Items.Add(new Separator());
}
} }
contextMenu.Items.Add(multiSelectMenuItem); contextMenu.Items.Add(multiSelectMenuItem);

165
ObjectAlignment.cs Normal file
View File

@ -0,0 +1,165 @@
using CtrEditor.ObjetosSim;
using System.Collections.ObjectModel;
using System.Windows;
namespace CtrEditor
{
public class ObjectAlignment
{
private readonly ObservableCollection<osBase> _selectedObjects;
public ObjectAlignment(ObservableCollection<osBase> selectedObjects)
{
_selectedObjects = selectedObjects;
}
public void AlignLeft()
{
if (_selectedObjects.Count <= 1) return;
float leftMost = _selectedObjects.Min(obj => obj.Left);
foreach (var obj in _selectedObjects)
{
obj.Left = leftMost;
}
}
public void AlignRight()
{
if (_selectedObjects.Count <= 1) return;
float rightMost = _selectedObjects.Max(obj => obj.Left + obj.Ancho);
foreach (var obj in _selectedObjects)
{
obj.Left = rightMost - obj.Ancho;
}
}
public void AlignTop()
{
if (_selectedObjects.Count <= 1) return;
float topMost = _selectedObjects.Min(obj => obj.Top);
foreach (var obj in _selectedObjects)
{
obj.Top = topMost;
}
}
public void AlignBottom()
{
if (_selectedObjects.Count <= 1) return;
float bottomMost = _selectedObjects.Max(obj => obj.Top + obj.Alto);
foreach (var obj in _selectedObjects)
{
obj.Top = bottomMost - obj.Alto;
}
}
public void AlignCenterHorizontally()
{
if (_selectedObjects.Count <= 1) return;
float averageY = _selectedObjects.Average(obj => obj.Top + obj.Alto / 2);
foreach (var obj in _selectedObjects)
{
obj.Top = averageY - obj.Alto / 2;
}
}
public void AlignCenterVertically()
{
if (_selectedObjects.Count <= 1) return;
float averageX = _selectedObjects.Average(obj => obj.Left + obj.Ancho / 2);
foreach (var obj in _selectedObjects)
{
obj.Left = averageX - obj.Ancho / 2;
}
}
public void DistributeHorizontally()
{
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)
})
.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);
// 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;
}
}
public void DistributeVertically()
{
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)
})
.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);
// 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;
}
}
private Point GetObjectCenter(osBase obj)
{
double angleRad = obj.Angulo * Math.PI / 180.0;
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);
return new Point(rotatedX, rotatedY);
}
return new Point(centerX, centerY);
}
}
}

View File

@ -11,6 +11,18 @@ using System.Collections.ObjectModel;
namespace CtrEditor namespace CtrEditor
{ {
public enum AlignmentType
{
Left,
Right,
Top,
Bottom,
CenterHorizontally,
CenterVertically,
DistributeHorizontally,
DistributeVertically
}
public class ObjectManipulationManager public class ObjectManipulationManager
{ {
private enum ResizeMode private enum ResizeMode
@ -69,7 +81,7 @@ namespace CtrEditor
} }
} }
private void UpdateSelectionVisuals() public void UpdateSelectionVisuals()
{ {
RemoveResizeRectangles(); RemoveResizeRectangles();
if (_selectedObjects.Any()) if (_selectedObjects.Any())
@ -719,5 +731,43 @@ namespace CtrEditor
UpdateSelectionHighlights(); UpdateSelectionHighlights();
} }
public void AlignObjects(AlignmentType alignmentType)
{
if (_selectedObjects.Count <= 1) return;
var alignment = new ObjectAlignment(_selectedObjects);
switch (alignmentType)
{
case AlignmentType.Left:
alignment.AlignLeft();
break;
case AlignmentType.Right:
alignment.AlignRight();
break;
case AlignmentType.Top:
alignment.AlignTop();
break;
case AlignmentType.Bottom:
alignment.AlignBottom();
break;
case AlignmentType.CenterHorizontally:
alignment.AlignCenterHorizontally();
break;
case AlignmentType.CenterVertically:
alignment.AlignCenterVertically();
break;
case AlignmentType.DistributeHorizontally:
alignment.DistributeHorizontally();
break;
case AlignmentType.DistributeVertically:
alignment.DistributeVertically();
break;
}
// Update the selection visuals after alignment
UpdateSelectionVisuals();
}
} }
} }