diff --git a/Commands/FileDialogCommand.cs b/Commands/FileDialogCommand.cs
new file mode 100644
index 0000000..e69de29
diff --git a/Converters/ActionConverter.cs b/Converters/ActionConverter.cs
new file mode 100644
index 0000000..e69de29
diff --git a/MainWindow.xaml b/MainWindow.xaml
index 14f4428..334aecd 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -342,8 +342,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 80a866a..61639d9 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -24,6 +24,7 @@ namespace CtrEditor
private bool _isDraggingCanvas = false;
private Image imagenDeFondo;
internal ObjectManipulationManager _objectManager;
+ private Rectangle _panningArea;
// Temporizadores y animación
private DispatcherTimer _zoomTimer;
@@ -44,6 +45,12 @@ namespace CtrEditor
_objectManager = new ObjectManipulationManager(this, ImagenEnTrabajoCanvas);
+ _panningArea = new Rectangle
+ {
+ Fill = Brushes.Transparent,
+ IsHitTestVisible = true
+ };
+
// Inicializar temporizador de zoom
_zoomTimer = new DispatcherTimer();
_zoomTimer.Interval = TimeSpan.FromMilliseconds(1);
@@ -53,9 +60,13 @@ namespace CtrEditor
// Suscribir eventos
this.Loaded += MainWindow_Loaded;
ImagenEnTrabajoScrollViewer.PreviewMouseWheel += ImagenEnTrabajoCanvas_MouseWheel;
+
ImagenEnTrabajoCanvas.MouseDown += Canvas_MouseDown_Panning;
ImagenEnTrabajoCanvas.MouseMove += Canvas_MouseMove_Panning;
ImagenEnTrabajoCanvas.MouseUp += Canvas_MouseUp_Panning;
+
+ _panningArea.MouseDown += Canvas_MouseDown_Panning;
+ _panningArea.MouseRightButtonDown += Canvas_MouseRightButtonDown;
this.KeyDown += MainWindow_KeyDown;
ImagenEnTrabajoCanvas.MouseEnter += Canvas_MouseEnter;
this.Closed += MainWindow_Closed;
@@ -114,20 +125,38 @@ namespace CtrEditor
imagenDeFondo.Source = bitmap;
RenderOptions.SetBitmapScalingMode(imagenDeFondo, BitmapScalingMode.HighQuality);
- // Elimina solo los ROIs, no la imagen de fondo
+ // Actualizar dimensiones del canvas
+ ImagenEnTrabajoCanvas.Width = bitmap.Width;
+ ImagenEnTrabajoCanvas.Height = bitmap.Height;
+
+ // Configurar el área de panning
+ _panningArea.Width = bitmap.Width * 4;
+ _panningArea.Height = bitmap.Height * 4;
+
+ // Posicionar el área de panning centrada respecto a la imagen
+ Canvas.SetLeft(_panningArea, -bitmap.Width / 4);
+ Canvas.SetTop(_panningArea, -bitmap.Height / 4);
+ Canvas.SetZIndex(_panningArea, -1); // Asegurar que está detrás de todo
+
+ // Asegurarse de que el área de panning está en el canvas
+ if (!ImagenEnTrabajoCanvas.Children.Contains(_panningArea))
+ {
+ ImagenEnTrabajoCanvas.Children.Add(_panningArea);
+ }
+
+ // Posicionar la imagen
+ Canvas.SetLeft(imagenDeFondo, 0);
+ Canvas.SetTop(imagenDeFondo, 0);
+
+ // Eliminar solo los ROIs, no la imagen de fondo ni el área de panning
for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--)
{
- if (ImagenEnTrabajoCanvas.Children[i] is not Image)
+ var child = ImagenEnTrabajoCanvas.Children[i];
+ if (child != imagenDeFondo && child != _panningArea)
{
ImagenEnTrabajoCanvas.Children.RemoveAt(i);
}
}
-
- ImagenEnTrabajoCanvas.Width = bitmap.Width;
- ImagenEnTrabajoCanvas.Height = bitmap.Height;
-
- Canvas.SetLeft(imagenDeFondo, 0);
- Canvas.SetTop(imagenDeFondo, 0);
}
private void Canvas_MouseUp_Panning(object sender, MouseButtonEventArgs e)
@@ -151,9 +180,10 @@ namespace CtrEditor
{
if (e.LeftButton == MouseButtonState.Pressed && !_isDrawingCanvas)
{
- // Verificar si el clic fue en el canvas, imagen de fondo o en el rectángulo de selección
- if (e.Source == ImagenEnTrabajoCanvas ||
+ // Permitir el panning cuando se hace clic en el área de panning o en la imagen
+ if (e.Source == _panningArea ||
e.Source == imagenDeFondo ||
+ e.Source == ImagenEnTrabajoCanvas ||
(e.Source is Rectangle rect && rect == _objectManager._selectionRectangle))
{
ImagenEnTrabajoCanvas.Focus();
@@ -173,7 +203,7 @@ namespace CtrEditor
{
_isDraggingCanvas = true;
_lastMousePosition = e.GetPosition(ImagenEnTrabajoScrollViewer);
- ImagenEnTrabajoCanvas.CaptureMouse();
+ ImagenEnTrabajoCanvas.CaptureMouse(); // Importante: siempre capturar en el Canvas principal
Mouse.OverrideCursor = Cursors.Hand;
if (DataContext is MainViewModel viewModel)
@@ -223,7 +253,7 @@ namespace CtrEditor
double minZoomFactor = Math.Min(
ImagenEnTrabajoScrollViewer.ViewportWidth / ImagenEnTrabajoCanvas.ActualWidth,
- ImagenEnTrabajoScrollViewer.ViewportHeight / ImagenEnTrabajoCanvas.ActualHeight);
+ ImagenEnTrabajoScrollViewer.ViewportHeight / ImagenEnTrabajoCanvas.ActualHeight)/1.5;
_targetZoomFactor = e.Delta > 0 ?
_initialZoomFactor * 1.4 :
@@ -310,6 +340,25 @@ namespace CtrEditor
}
}
+ private void ImagePathButton_Click(object sender, RoutedEventArgs e)
+ {
+ var dlg = new Ookii.Dialogs.Wpf.VistaOpenFileDialog
+ {
+ Filter = "Image files (*.png;*.jpg;*.bmp)|*.png;*.jpg;*.bmp|All files (*.*)|*.*"
+ };
+
+ if (dlg.ShowDialog() == true)
+ {
+ // El DataContext de este botón es el PropertyItem asociado
+ if ((sender as Button)?.DataContext is Xceed.Wpf.Toolkit.PropertyGrid.PropertyItem propertyItem)
+ {
+ propertyItem.Value = dlg.FileName;
+ }
+ }
+ }
+
+
+
private void MainWindow_KeyDown(object sender, KeyEventArgs e)
{
// Only force canvas focus if PanelEdicion doesn't have focus
diff --git a/ObjectManipulationManager.cs b/ObjectManipulationManager.cs
index 966e621..d596a55 100644
--- a/ObjectManipulationManager.cs
+++ b/ObjectManipulationManager.cs
@@ -259,19 +259,32 @@ namespace CtrEditor
return rect;
}
- private void AddResizeHandles(FuncionesBase.MutableRect rectBox, double rectSize,
+ private void AddResizeHandles(FuncionesBase.MutableRect rectBox, double defaultRectSize,
Cursor rotationCursorRx, Cursor rotationCursorSx)
{
+ // 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;
+
var positions = new List<(Point Position, string Tag, Cursor Cursor, Brush Stroke)>
{
- (new Point(rectBox.Left, rectBox.Top), "TopLeft", Cursors.Arrow, Brushes.Gray),
- (new Point(rectBox.Right, rectBox.Top), "TopRight", rotationCursorRx, Brushes.Red),
- (new Point(rectBox.Left, rectBox.Bottom), "BottomLeft", rotationCursorSx, Brushes.DarkRed),
- (new Point(rectBox.Right, rectBox.Bottom), "BottomRight", Cursors.SizeNWSE, Brushes.Blue),
- (new Point(rectBox.Left + rectBox.Width / 2, rectBox.Top), "TopCenter", Cursors.Arrow, Brushes.Gray),
- (new Point(rectBox.Left + rectBox.Width / 2, rectBox.Bottom), "BottomCenter", Cursors.SizeNS, Brushes.Blue),
- (new Point(rectBox.Left, rectBox.Top + rectBox.Height / 2), "CenterLeft", rotationCursorRx, Brushes.Red),
- (new Point(rectBox.Right, rectBox.Top + rectBox.Height / 2), "CenterRight", Cursors.SizeWE, Brushes.Blue)
+ // Esquinas - mover hacia afuera del rectángulo
+ (new Point(rectBox.Left - offset, rectBox.Top - offset), "TopLeft", Cursors.Arrow, Brushes.Gray),
+ (new Point(rectBox.Right + offset, rectBox.Top - offset), "TopRight", rotationCursorRx, Brushes.Red),
+ (new Point(rectBox.Left - offset, rectBox.Bottom + offset), "BottomLeft", rotationCursorSx, Brushes.DarkRed),
+ (new Point(rectBox.Right + offset, rectBox.Bottom + offset), "BottomRight", Cursors.SizeNWSE, Brushes.Blue),
+
+ // Centros de los bordes - mover hacia afuera del rectángulo
+ (new Point(rectBox.Left + rectBox.Width / 2, rectBox.Top - offset), "TopCenter", Cursors.Arrow, Brushes.Gray),
+ (new Point(rectBox.Left + rectBox.Width / 2, rectBox.Bottom + offset), "BottomCenter", Cursors.SizeNS, Brushes.Blue),
+ (new Point(rectBox.Left - offset, rectBox.Top + rectBox.Height / 2), "CenterLeft", rotationCursorRx, Brushes.Red),
+ (new Point(rectBox.Right + offset, rectBox.Top + rectBox.Height / 2), "CenterRight", Cursors.SizeWE, Brushes.Blue)
};
foreach (var (Position, Tag, Cursor, Stroke) in positions)
diff --git a/ObjetosSim/Decorativos/ucCustomImage.xaml b/ObjetosSim/Decorativos/ucCustomImage.xaml
new file mode 100644
index 0000000..5c9e1c1
--- /dev/null
+++ b/ObjetosSim/Decorativos/ucCustomImage.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/ObjetosSim/Decorativos/ucCustomImage.xaml.cs b/ObjetosSim/Decorativos/ucCustomImage.xaml.cs
new file mode 100644
index 0000000..4e47df3
--- /dev/null
+++ b/ObjetosSim/Decorativos/ucCustomImage.xaml.cs
@@ -0,0 +1,94 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using LibS7Adv;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using CtrEditor.FuncionesBase;
+using System.ComponentModel;
+using Newtonsoft.Json;
+
+namespace CtrEditor.ObjetosSim
+{
+ ///
+ /// A custom image control that can display an image from a file path
+ ///
+ public partial class osCustomImage : osBase, IosBase
+ {
+ public static string NombreClase()
+ {
+ return "Custom Image";
+ }
+
+ private string nombre = NombreClase();
+ public override string Nombre
+ {
+ get => nombre;
+ set => SetProperty(ref nombre, value);
+ }
+
+
+ [ObservableProperty]
+ [NotifyPropertyChangedFor(nameof(ImageSource_oculta))]
+ [property: Description("Path to the image file")]
+ [property: Category("Image:")]
+ private string imagePath;
+
+
+ [JsonIgnore]
+ [ObservableProperty]
+ public ImageSource imageSource_oculta;
+
+ partial void OnImagePathChanged(string value)
+ {
+ if (!string.IsNullOrEmpty(value))
+ {
+ ImageSource_oculta = ImageFromPath(value);
+ }
+ }
+
+ public osCustomImage()
+ {
+ Ancho = 0.30f;
+ Alto = 0.30f;
+ }
+
+ public override void ucLoaded()
+ {
+ base.ucLoaded();
+ if (!string.IsNullOrEmpty(ImagePath))
+ {
+ ImageSource_oculta = ImageFromPath(ImagePath);
+ }
+ }
+ }
+
+ public partial class ucCustomImage : UserControl, IDataContainer
+ {
+ public osBase? Datos { get; set; }
+ public int zIndex_fromFrames { get; set; }
+
+ public ucCustomImage()
+ {
+ InitializeComponent();
+ this.Loaded += OnLoaded;
+ this.Unloaded += OnUnloaded;
+ }
+
+ private void OnLoaded(object sender, RoutedEventArgs e)
+ {
+ Datos?.ucLoaded();
+ }
+
+ private void OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ Datos?.ucUnLoaded();
+ }
+
+ public void Highlight(bool State) { }
+
+ public ZIndexEnum ZIndex_Base()
+ {
+ return ZIndexEnum.Estaticos;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ObjetosSim/UserControlFactory.cs b/ObjetosSim/UserControlFactory.cs
index bb9bb8b..749d96c 100644
--- a/ObjetosSim/UserControlFactory.cs
+++ b/ObjetosSim/UserControlFactory.cs
@@ -96,45 +96,52 @@ namespace CtrEditor.ObjetosSim
public static void CargarPropiedadesosDatos(object selectedObject, PropertyGrid propertyGrid)
{
- // Clear previous properties
+ // Limpia las propiedades previas
propertyGrid.SelectedObject = null;
propertyGrid.PropertyDefinitions.Clear();
- // Add properties dynamically based on attributes
+ // Obtén las propiedades del objeto (excluyendo las que tengan HiddenAttribute)
var properties = TypeDescriptor.GetProperties(selectedObject)
.Cast()
- .Where(prop => !prop.Attributes.OfType().Any()).OrderBy(prop => prop.Name);
+ .Where(prop => !prop.Attributes.OfType().Any())
+ .OrderBy(prop => prop.Name);
foreach (var property in properties)
{
+ if (property.Name.EndsWith("_oculto"))
+ continue;
+
var displayNameAttr = property.Attributes.OfType().FirstOrDefault();
var propertyDefinition = new PropertyDefinition
{
- TargetProperties = new[] { property.Name }
+ TargetProperties = new[] { property.Name },
+ DisplayName = displayNameAttr != null
+ ? displayNameAttr.DisplayName
+ : property.Name.Replace("_", " ")
};
- if (!property.Name.EndsWith("_oculto"))
+ // Aquí se añaden todas las propiedades; para "ImagePath" no se requiere
+ // ninguna configuración adicional, pues el EditorTemplateDefinition en XAML se
+ // aplicará automáticamente.
+ if (property.PropertyType == typeof(double) ||
+ property.PropertyType == typeof(float) ||
+ property.PropertyType == typeof(string) ||
+ property.PropertyType == typeof(int) ||
+ property.PropertyType == typeof(bool) ||
+ property.PropertyType == typeof(osBase) ||
+ property.PropertyType == typeof(osVMmotorSim) ||
+ property.PropertyType == typeof(osBuscarCoincidencias) ||
+ property.PropertyType == typeof(Color))
{
- if (displayNameAttr != null)
- {
- propertyDefinition.DisplayName = displayNameAttr.DisplayName;
- }
- else
- {
- propertyDefinition.DisplayName = property.Name.Replace("_", " ");
- }
- if (property.PropertyType == typeof(double) || property.PropertyType == typeof(float) || property.PropertyType == typeof(string) || property.PropertyType == typeof(int) ||
- property.PropertyType == typeof(bool) || property.PropertyType == typeof(osBase) ||
- property.PropertyType == typeof(osVMmotorSim) || property.PropertyType == typeof(osBuscarCoincidencias) || property.PropertyType == typeof(Color) )
- {
- propertyGrid.PropertyDefinitions.Add(propertyDefinition);
- }
+ propertyGrid.PropertyDefinitions.Add(propertyDefinition);
}
}
propertyGrid.SelectedObject = selectedObject;
}
+
+
}
}