diff --git a/CtrEditor.csproj b/CtrEditor.csproj index b4389f1..ee4c224 100644 --- a/CtrEditor.csproj +++ b/CtrEditor.csproj @@ -9,6 +9,7 @@ + diff --git a/DatosDeTrabajo.cs b/DatosDeTrabajo.cs index 369b4cc..9aceba4 100644 --- a/DatosDeTrabajo.cs +++ b/DatosDeTrabajo.cs @@ -18,6 +18,16 @@ namespace CtrEditor CargarImagenes(); // Inicializar la carga de imágenes basada en el directorio persistente } + public string ObtenerPathImagenConExtension(string key, string extension) + { + if (Imagenes.TryGetValue(key, out string imagePath)) + { + string jsonPath = Path.ChangeExtension(imagePath, extension); + return jsonPath; + } + return null; + } + public void CargarImagenes() { Imagenes.Clear(); diff --git a/ICtrSimulado.cs b/ICtrSimulado.cs deleted file mode 100644 index 54fbedf..0000000 --- a/ICtrSimulado.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace CtrEditor -{ - public interface ICtrSimulado - { - string Nombre { get; } - void Update(); - // other common methods and properties - } -} diff --git a/MainViewModel.cs b/MainViewModel.cs index df7a70f..a2c97a2 100644 --- a/MainViewModel.cs +++ b/MainViewModel.cs @@ -1,5 +1,4 @@ -using CtrEditor; -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -9,54 +8,105 @@ using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Input; using Ookii.Dialogs.Wpf; -using System.Windows.Input; using System.Collections.ObjectModel; using System.Windows.Media; using System.Windows.Media.Imaging; using static System.Runtime.InteropServices.JavaScript.JSType; using System.Windows.Threading; +using CtrEditor.ObjetosSim; +using System.IO; +using System.Windows.Forms; +using System.Text.Json.Serialization; +using System.Text.Json; +using Newtonsoft.Json; namespace CtrEditor { - public class TickSimulacionEventArgs : EventArgs - { - // Aquí puedes agregar propiedades o campos para pasar información adicional - // en el evento TickSimulacion - } - public class MainViewModel : INotifyPropertyChanged { public DatosDeTrabajo datosDeTrabajo { get; } - public ObservableCollection listaImagenes { get; private set; } // Publicación de las claves del diccionario - private ObservableCollection _funciones; + public ObservableCollection listaImagenes { get; private set; } // Publicación de las claves del diccionario + public ObservableCollection ListaOsBase { get; } = new ObservableCollection(); + private readonly DispatcherTimer _timerSimulacion; - private string _selectedImage; + + public ICommand StartSimulationCommand { get; } + public ICommand StopSimulationCommand { get; } + public ICommand ItemDoubleClickCommand { get; private set; } + // Evento que se dispara cuando se selecciona una nueva imagen public event EventHandler ImageSelected; public event EventHandler TickSimulacion; + public event Action OnUserControlSelected; public MainViewModel() { OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory); datosDeTrabajo = new DatosDeTrabajo(); - listaImagenes = new ObservableCollection(datosDeTrabajo.Imagenes.Keys); - _funciones = new ObservableCollection(); - _funciones.Add(new OSBotella()); - _funciones.Add(new OSPack()); - directorioTrabajo = EstadoPersistente.Instance.directorio; + + InitializeTipoSimulableList(); + + ItemDoubleClickCommand = new ParameterizedRelayCommand(ExecuteDoubleClick); _timerSimulacion = new DispatcherTimer(); _timerSimulacion.Interval = TimeSpan.FromMilliseconds(100); // ajusta el intervalo según sea necesario _timerSimulacion.Tick += OnTickSimulacion; StartSimulationCommand = new RelayCommand(StartSimulation); - StopSimulationCommand = new RelayCommand(StopSimulation); + StopSimulationCommand = new RelayCommand(StopSimulation); + + } + + public void LoadInitialData() + { + // Suponiendo que "SelectedImage" es una propiedad que al establecerse dispara "ImageSelected" + directorioTrabajo = EstadoPersistente.Instance.directorio; + } + + + private TipoSimulable _selectedItem = null; + public TipoSimulable SelectedItem + { + get => _selectedItem; + set + { + if (_selectedItem != value) + { + _selectedItem = value; + OnPropertyChanged(nameof(SelectedItem)); // Notificar que la propiedad ha cambiado + } + } + } + + + private void ExecuteDoubleClick(object parameter) + { + if (parameter is TipoSimulable tipoSimulable) + { + var instance = Activator.CreateInstance(tipoSimulable.Tipo) as osBase; + if (instance != null) + { + ObjetosSimulables.Add(instance); + OnUserControlSelected?.Invoke(instance); + } + } + } + + private void InitializeTipoSimulableList() + { + var baseType = typeof(osBase); + var types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(assembly => assembly.GetTypes()) + .Where(type => type.IsSubclassOf(baseType) && !type.IsAbstract); + + foreach (var type in types) + { + ListaOsBase.Add(new TipoSimulable { Nombre = type.Name, Tipo = type }); + } } - public ICommand StartSimulationCommand { get; } - public ICommand StopSimulationCommand { get; } private void StartSimulation() { @@ -90,33 +140,33 @@ namespace CtrEditor EstadoPersistente.Instance.GuardarEstado(); // Guardar el estado actualizado datosDeTrabajo.CargarImagenes(); listaImagenes = new ObservableCollection(datosDeTrabajo.Imagenes.Keys); // Actualizar claves + SelectedImage = null; + if (listaImagenes.FirstOrDefault() != null) + SelectedImage = listaImagenes.FirstOrDefault(); OnPropertyChanged(nameof(directorioTrabajo)); // Notificar el cambio de propiedad OnPropertyChanged(nameof(listaImagenes)); // Notificar que la lista de imágenes ha cambiado } } } - public ObservableCollection CtrSimulado - { - get { return _funciones; } - set { _funciones = value; } - } - + private string _selectedImage = null; public string SelectedImage { get => _selectedImage; set { - if (_selectedImage != value) + if (_selectedImage != value && value != null) { + SaveStateObjetosSimulables(); // Guarda el estado antes de cambiar la imagen _selectedImage = value; - OnPropertyChanged(nameof(SelectedImage)); + LoadStateObjetosSimulables(); ImageSelected?.Invoke(this, datosDeTrabajo.Imagenes[value]); // Dispara el evento con la nueva ruta de imagen } + _selectedImage = value; + OnPropertyChanged(nameof(SelectedImage)); } } - - + public ICommand OpenWorkDirectoryCommand { get; } private void OpenWorkDirectory() @@ -128,6 +178,74 @@ namespace CtrEditor } } + // + // Lista de osBase + // + private ObservableCollection objetosSimulables = new ObservableCollection(); + + public ObservableCollection ObjetosSimulables + { + get => objetosSimulables; + set + { + if (objetosSimulables != value) + { + objetosSimulables = value; + OnPropertyChanged(nameof(ObjetosSimulables)); + } + } + } + + + + public void SaveStateObjetosSimulables() + { + if (_selectedImage != null) + { + var settings = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore, + TypeNameHandling = TypeNameHandling.Auto + }; + foreach (var obj in objetosSimulables) + { + obj.VisualRepresentation = null; + } + var serializedData = JsonConvert.SerializeObject(objetosSimulables, settings); + File.WriteAllText(datosDeTrabajo.ObtenerPathImagenConExtension(_selectedImage, ".json"), serializedData); + } + } + + public void LoadStateObjetosSimulables() + { + try + { + ObjetosSimulables.Clear(); + if (_selectedImage != null) + { + string jsonPath = datosDeTrabajo.ObtenerPathImagenConExtension(_selectedImage, ".json"); + if (File.Exists(jsonPath)) + { + string jsonString = File.ReadAllText(jsonPath); + var settings = new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Auto, + ObjectCreationHandling = ObjectCreationHandling.Replace, + PreserveReferencesHandling = PreserveReferencesHandling.Objects, + ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor + }; + objetosSimulables = JsonConvert.DeserializeObject>(jsonString, settings); + + foreach (var obj in objetosSimulables) + { + OnUserControlSelected?.Invoke(obj); + } + } + } + } + catch { /* Consider logging the error or handling it appropriately */ } + } // Implementación de INotifyPropertyChanged... @@ -137,6 +255,19 @@ namespace CtrEditor PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } + + } + + public class TipoSimulable + { + public string Nombre { get; set; } + public Type Tipo { get; set; } + } + + public class TickSimulacionEventArgs : EventArgs + { + // Aquí puedes agregar propiedades o campos para pasar información adicional + // en el evento TickSimulacion } } diff --git a/MainWindow.xaml b/MainWindow.xaml index e1332c5..0d6ec2b 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -1,6 +1,8 @@  @@ -35,7 +37,13 @@ - + + + + + + + @@ -43,7 +51,7 @@ - + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 2db11cd..44eb6f3 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -8,6 +8,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using CtrEditor.ObjetosSim; namespace CtrEditor { @@ -36,8 +37,56 @@ namespace CtrEditor { viewModel.ImageSelected += ViewModel_ImageSelected; viewModel.TickSimulacion += MainViewModel_TickSimulacion; + viewModel.OnUserControlSelected += AgregarUserControl; + viewModel?.LoadInitialData(); // Carga la primera imagen por defecto una vez cargada la ventana principal } } + + private void AgregarUserControl(osBase NuevoOS) + { + if (NuevoOS != null) + { + if (NuevoOS.VisualRepresentation is null) + { + UserControl userControl = UserControlFactory.GetControlForType(NuevoOS.GetType()); + NuevoOS.VisualRepresentation = userControl; + + if (!NuevoOS.Inicializado) // Aun no fue inicializado + { + // Obtiene el área visible del ScrollViewer + var visibleWidth = ImagenEnTrabajoScrollViewer.ViewportWidth; + var visibleHeight = ImagenEnTrabajoScrollViewer.ViewportHeight; + + // Obtiene la posición actual del desplazamiento + var offsetX = ImagenEnTrabajoScrollViewer.HorizontalOffset; + var offsetY = ImagenEnTrabajoScrollViewer.VerticalOffset; + + // Calcula el centro visible del Canvas + double centerX = offsetX + visibleWidth / 2; + double centerY = offsetY + visibleHeight / 2; + + // Ajusta la posición del UserControl para que esté centrado en el área visible + double left = centerX - (userControl.ActualWidth / 2); + double top = centerY - (userControl.ActualHeight / 2); + + // Establece la posición del UserControl + Canvas.SetLeft(userControl, left); + Canvas.SetTop(userControl, top); + + NuevoOS.x = left; + NuevoOS.y = top; + + NuevoOS.Inicializado = true; + } + + // Añade el UserControl al Canvas + ImagenEnTrabajoCanvas.Children.Add(userControl); + } + } + } + + + private void ViewModel_ImageSelected(object sender, string imagePath) { LoadImageToCanvas(imagePath); @@ -59,7 +108,7 @@ namespace CtrEditor // Elimina solo los ROIs, no la imagen de fondo for (int i = ImagenEnTrabajoCanvas.Children.Count - 1; i >= 0; i--) { - if (ImagenEnTrabajoCanvas.Children[i] is Rectangle) + if (ImagenEnTrabajoCanvas.Children[i] is not Image) { ImagenEnTrabajoCanvas.Children.RemoveAt(i); } @@ -146,7 +195,7 @@ namespace CtrEditor // en el ImagenEnTrabajoCanvas foreach (var child in ImagenEnTrabajoCanvas.Children) { - if (child is ICtrSimulado uc) + if (child is osBase uc) { // llama al método Update de cada UserControl uc.Update(); diff --git a/OSPack.xaml b/OSPack.xaml deleted file mode 100644 index 4521a6b..0000000 --- a/OSPack.xaml +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/ObjetosSim/UserControlFactory.cs b/ObjetosSim/UserControlFactory.cs new file mode 100644 index 0000000..b3118ff --- /dev/null +++ b/ObjetosSim/UserControlFactory.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; + +namespace CtrEditor.ObjetosSim +{ + public static class UserControlFactory + { + public static UserControl GetControlForType(Type tipoObjeto) + { + if (tipoObjeto == typeof(osBotella)) + return new ucBotella(); + if (tipoObjeto == typeof(osTransporteTTop)) + return new ucTransporteTTop(); + + // Puedes añadir más condiciones para otros tipos + + + return null; + } + } + +} diff --git a/ObjetosSim/osBase.cs b/ObjetosSim/osBase.cs new file mode 100644 index 0000000..151a684 --- /dev/null +++ b/ObjetosSim/osBase.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using System.Windows.Controls; + +namespace CtrEditor.ObjetosSim +{ + + public interface IosBase + { + string Nombre { get; } + void Update(); + } + + + public abstract class osBase : IosBase + { + private UserControl? _visualRepresentation = null; + + [JsonIgnore] + public UserControl? VisualRepresentation + { + get => _visualRepresentation; + set => _visualRepresentation = value; + } + + // Método para inicializar la representación visual, si es necesario + //public void InitializeVisualRepresentation() + //{ + // // Suponiendo que existe un método estático para obtener el UserControl adecuado + // _visualRepresentation = UserControlFactory.GetControlForType(this.GetType()); + //} + public string Nombre => "Base"; + public abstract void Update(); + public bool Inicializado = false; + public double x { get; set; } + public double y { get; set; } + + + } +} diff --git a/OSBotella.xaml b/ObjetosSim/ucBotella.xaml similarity index 67% rename from OSBotella.xaml rename to ObjetosSim/ucBotella.xaml index 4f6e727..d85b0cd 100644 --- a/OSBotella.xaml +++ b/ObjetosSim/ucBotella.xaml @@ -1,6 +1,5 @@ - + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + \ No newline at end of file diff --git a/OSPack.xaml.cs b/ObjetosSim/ucBotella.xaml.cs similarity index 57% rename from OSPack.xaml.cs rename to ObjetosSim/ucBotella.xaml.cs index 37de810..4dff6c7 100644 --- a/OSPack.xaml.cs +++ b/ObjetosSim/ucBotella.xaml.cs @@ -13,22 +13,30 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; -namespace CtrEditor +namespace CtrEditor.ObjetosSim { /// - /// Interaction logic for ObjetoSimuladoPack.xaml + /// Interaction logic for ucBotella.xaml /// - public partial class OSPack : UserControl, ICtrSimulado + /// + + public class osBotella : osBase { - public OSPack() - { - InitializeComponent(); - } - public string Nombre => "Packs"; - public void Update() + public double diametro { get; set; } + // Otros datos y métodos relevantes para la simulación + + public new string Nombre => "Botella"; + public override void Update() { // implementation of Update method } } + public partial class ucBotella : UserControl + { + public ucBotella() + { + InitializeComponent(); + } + } } diff --git a/ObjetosSim/ucTransporteTTop.xaml b/ObjetosSim/ucTransporteTTop.xaml new file mode 100644 index 0000000..97dc6d1 --- /dev/null +++ b/ObjetosSim/ucTransporteTTop.xaml @@ -0,0 +1,9 @@ + + + diff --git a/OSBotella.cs b/ObjetosSim/ucTransporteTTop.xaml.cs similarity index 55% rename from OSBotella.cs rename to ObjetosSim/ucTransporteTTop.xaml.cs index 3d21aeb..d49c658 100644 --- a/OSBotella.cs +++ b/ObjetosSim/ucTransporteTTop.xaml.cs @@ -13,22 +13,30 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; -namespace CtrEditor +namespace CtrEditor.ObjetosSim { /// - /// Interaction logic for ObjetoSimuladoBotella.xaml + /// Interaction logic for ucTransporteTTop.xaml /// - public partial class OSBotella : UserControl, ICtrSimulado + /// + + public class osTransporteTTop : osBase { - public OSBotella() - { - InitializeComponent(); - } - public string Nombre => "Botellas"; - public void Update() + public double diametro { get; set; } + // Otros datos y métodos relevantes para la simulación + + public new string Nombre => "Transporte TTOP"; + public override void Update() { // implementation of Update method } } + public partial class ucTransporteTTop : UserControl + { + public ucTransporteTTop() + { + InitializeComponent(); + } + } } diff --git a/RelayCommand.cs b/RelayCommand.cs index 3b3d68e..b78e564 100644 --- a/RelayCommand.cs +++ b/RelayCommand.cs @@ -39,4 +39,37 @@ namespace CtrEditor CommandManager.InvalidateRequerySuggested(); } } + public class ParameterizedRelayCommand : ICommand + { + private readonly Action _execute; + private readonly Predicate _canExecute; + + public ParameterizedRelayCommand(Action execute, Predicate canExecute = null) + { + _execute = execute ?? throw new ArgumentNullException(nameof(execute)); + _canExecute = canExecute; + } + + public bool CanExecute(object parameter) + { + return _canExecute == null || _canExecute(parameter); + } + + public void Execute(object parameter) + { + _execute(parameter); + } + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public void RaiseCanExecuteChanged() + { + CommandManager.InvalidateRequerySuggested(); + } + } + } diff --git a/estadoPersistente.cs b/estadoPersistente.cs index 0c8b03a..1f54424 100644 --- a/estadoPersistente.cs +++ b/estadoPersistente.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Newtonsoft.Json; using System; using System.IO; +using System.Text.Json; namespace CtrEditor { @@ -28,9 +28,14 @@ namespace CtrEditor } // Constructor privado para evitar la instanciación externa - private EstadoPersistente() + public EstadoPersistente() + { + } + + private EstadoPersistente Inizializar() { _strDirectorioTrabajo = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + return this; } // Propiedad pública estática para acceder a la instancia @@ -47,21 +52,34 @@ namespace CtrEditor } // Método para guardar el estado en un archivo JSON + + public void GuardarEstado() { - string json = JsonConvert.SerializeObject(this); + var options = new JsonSerializerOptions + { + WriteIndented = true // para una salida JSON formateada legiblemente + }; + string json = JsonSerializer.Serialize(this, options); File.WriteAllText(_filePath, json); } + // Método estático para cargar el estado desde un archivo JSON private static EstadoPersistente CargarEstado() { - if (File.Exists(_filePath)) + try { - string json = File.ReadAllText(_filePath); - return JsonConvert.DeserializeObject(json); + if (File.Exists(_filePath)) + { + string json = File.ReadAllText(_filePath); + return JsonSerializer.Deserialize(json); + } + return new EstadoPersistente().Inizializar(); // Devuelve una nueva instancia si no existe el archivo + } catch + { + return new EstadoPersistente().Inizializar(); // Devuelve una nueva instancia si no existe el archivo } - return new EstadoPersistente(); // Devuelve una nueva instancia si no existe el archivo } }