using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using CommunityToolkit.Mvvm.ComponentModel; using CtrEditor.FuncionesBase; using DocumentFormat.OpenXml.Spreadsheet; using Newtonsoft.Json; using Xceed.Wpf.Toolkit.PropertyGrid.Attributes; using Color = System.Windows.Media.Color; using Colors = System.Windows.Media.Colors; using JsonIgnoreAttribute = Newtonsoft.Json.JsonIgnoreAttribute; namespace CtrEditor.ObjetosSim { /// /// Interaction logic for ucFramePlate.xaml /// /// public partial class osFramePlate : osBase, IosBase { [JsonIgnore] public float offsetY; [JsonIgnore] public float offsetX; [JsonIgnore] public float offsetAngulo; public static string NombreClase() { return "Marco de Panel"; } private string nombre = NombreClase(); [property: Category("Identificación")] [property: Description("Nombre identificativo del objeto")] [property: Name("Nombre")] public override string Nombre { get => nombre; set => SetProperty(ref nombre, value); } [ObservableProperty] [property: Description("Índice de capa para objetos en el marco")] [property: Category("Configuración")] [property: Name("Índice Z del Marco")] int zindex_FramePlate; partial void OnZindex_FramePlateChanged(int value) { UpdateZIndex(value); } [ObservableProperty] [property: Category("Apariencia")] [property: Description("Color de fondo del marco")] [property: Name("Color")] Color color; [ObservableProperty] [property: Category("Apariencia")] [property: Description("Color del texto del título")] [property: Name("Color del Título")] Color color_Titulo; [ObservableProperty] [property: Category("Configuración")] [property: Description("Texto del título del marco")] [property: Name("Título")] string titulo; [ObservableProperty] [property: Category("Configuración")] [property: Description("Alto del área del título")] [property: Name("Alto del Título")] public float alto_Titulo; // Encoder X [ObservableProperty] [property: Description("This is a link to a Encoder for X.")] [property: Category("Encoders:")] [property: ItemsSource(typeof(osBaseItemsSource))] private string encoder_X; [ObservableProperty] [property: Description("K Pulses per meter for Moving")] [property: Category("Encoders:")] public float k_encoder_X; [ObservableProperty] [property: ReadOnly(true)] [property: Description("Actual Position X")] [property: Category("Encoders:")] public float encoder_X_Position; [ObservableProperty] [property: Description("X in meter offset Left. Position when the encoder is 0")] [property: Category("Encoders:")] public float offset_encoder_X; // Encoder Y [ObservableProperty] [property: Description("This is a link to a Encoder for Y.")] [property: Category("Encoders:")] [property: ItemsSource(typeof(osBaseItemsSource))] private string encoder_Y; [ObservableProperty] [property: Description("K Pulses per meter for Moving")] [property: Category("Encoders:")] public float k_encoder_Y; [ObservableProperty] [property: ReadOnly(true)] [property: Description("Actual Position Y")] [property: Category("Encoders:")] public float encoder_Y_Position; [ObservableProperty] [property: Description("Y in meter offset Top. Position when the encoder is 0")] [property: Category("Encoders:")] public float offset_encoder_Y; // Encoder Rotation [ObservableProperty] [property: Description("This is a link to a Encoder for Rotation.")] [property: Category("Encoders:")] [property: ItemsSource(typeof(osBaseItemsSource))] private string encoder_Rotation; [ObservableProperty] [property: Description("K Pulses per degree for Rotation")] [property: Category("Encoders:")] public float k_encoder_Rotation; [ObservableProperty] [property: ReadOnly(true)] [property: Description("Actual Rotation Angle")] [property: Category("Encoders:")] public float encoder_Rotation_Angle; [ObservableProperty] [property: Description("Angle in degrees offset. Angle when the encoder is 0")] [property: Category("Encoders:")] public float offset_encoder_Rotation; partial void OnK_encoder_YChanged(float value) { UpdatePosition(); } partial void OnOffset_encoder_YChanged(float value) { UpdatePosition(); } partial void OnK_encoder_XChanged(float value) { UpdatePosition(); } partial void OnOffset_encoder_XChanged(float value) { UpdatePosition(); } partial void OnK_encoder_RotationChanged(float value) { UpdatePosition(); } partial void OnOffset_encoder_RotationChanged(float value) { UpdatePosition(); } [JsonIgnore] private osEncoderMotorLineal EncoderX; [JsonIgnore] private osEncoderMotorLineal EncoderY; [JsonIgnore] private osEncoderMotorLineal EncoderRotation; [JsonIgnore] private bool isUpdatingFromEncoderX = false; [JsonIgnore] private bool isUpdatingFromEncoderY = false; [JsonIgnore] private bool isUpdatingFromEncoderRotation = false; partial void OnEncoder_XChanged(string value) { if (EncoderX != null) EncoderX.PropertyChanged -= OnEncoderXPropertyChanged; if (_mainViewModel != null && value != null && value.Length > 0) { EncoderX = (osEncoderMotorLineal)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osEncoderMotorLineal && s.Nombre == value), null); if (EncoderX != null) EncoderX.PropertyChanged += OnEncoderXPropertyChanged; } } partial void OnEncoder_YChanged(string value) { if (EncoderY != null) EncoderY.PropertyChanged -= OnEncoderYPropertyChanged; if (_mainViewModel != null && value != null && value.Length > 0) { EncoderY = (osEncoderMotorLineal)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osEncoderMotorLineal && s.Nombre == value), null); if (EncoderY != null) EncoderY.PropertyChanged += OnEncoderYPropertyChanged; } } partial void OnEncoder_RotationChanged(string value) { if (EncoderRotation != null) EncoderRotation.PropertyChanged -= OnEncoderRotationPropertyChanged; if (_mainViewModel != null && value != null && value.Length > 0) { EncoderRotation = (osEncoderMotorLineal)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => (s is osEncoderMotorLineal && s.Nombre == value), null); if (EncoderRotation != null) EncoderRotation.PropertyChanged += OnEncoderRotationPropertyChanged; } } private void OnEncoderXPropertyChanged(object sender, PropertyChangedEventArgs e) { if (!isUpdatingFromEncoderX) { isUpdatingFromEncoderX = true; // Actualizamos el nombre si este fue modificado if (e.PropertyName == nameof(osEncoderMotorLineal.Nombre)) Encoder_X = ((osEncoderMotorLineal)sender).Nombre; if (e.PropertyName == nameof(osEncoderMotorLineal.Valor_Actual)) { UpdatePosition(); } isUpdatingFromEncoderX = false; } } private void OnEncoderYPropertyChanged(object sender, PropertyChangedEventArgs e) { if (!isUpdatingFromEncoderY) { isUpdatingFromEncoderY = true; // Actualizamos el nombre si este fue modificado if (e.PropertyName == nameof(osEncoderMotorLineal.Nombre)) Encoder_Y = ((osEncoderMotorLineal)sender).Nombre; if (e.PropertyName == nameof(osEncoderMotorLineal.Valor_Actual)) { UpdatePosition(); } isUpdatingFromEncoderY = false; } } private void OnEncoderRotationPropertyChanged(object sender, PropertyChangedEventArgs e) { if (!isUpdatingFromEncoderRotation) { isUpdatingFromEncoderRotation = true; // Actualizamos el nombre si este fue modificado if (e.PropertyName == nameof(osEncoderMotorLineal.Nombre)) Encoder_Rotation = ((osEncoderMotorLineal)sender).Nombre; if (e.PropertyName == nameof(osEncoderMotorLineal.Valor_Actual)) { UpdatePosition(); } isUpdatingFromEncoderRotation = false; } } public void UpdatePosition() { // Update X position if encoder is available if (EncoderX != null && K_encoder_X != 0) { Encoder_X_Position = EncoderX.Valor_Actual; Left = (Encoder_X_Position / k_encoder_X) + offset_encoder_X; } // Update Y position if encoder is available if (EncoderY != null && K_encoder_Y != 0) { Encoder_Y_Position = EncoderY.Valor_Actual; Top = (Encoder_Y_Position / k_encoder_Y) + offset_encoder_Y; } // Update rotation angle if encoder is available if (EncoderRotation != null && K_encoder_Rotation != 0) { Encoder_Rotation_Angle = EncoderRotation.Valor_Actual; Angulo = (Encoder_Rotation_Angle / k_encoder_Rotation) + offset_encoder_Rotation; } } public override void TopChanging(float oldValue, float newValue) { offsetY = newValue - oldValue; } public override void LeftChanging(float oldValue, float newValue) { offsetX = newValue - oldValue; } public override void AnguloChanging(float oldValue, float newValue) { offsetAngulo = newValue - oldValue; } [ObservableProperty] [property: Description("Show/Hide the plate background")] [property: Category("Appearance:")] private bool showPlate; [ObservableProperty] [property: Description("Use horizontal center as pivot point for rotation")] [property: Category("Pivot:")] private bool pivotCenterX; [ObservableProperty] [property: Description("Use vertical center as pivot point for rotation")] [property: Category("Pivot:")] private bool pivotCenterY; partial void OnPivotCenterXChanged(bool value) { // Notificar cambio de pivot para actualizar objetos conectados OnPropertyChanged(nameof(PivotCenterX)); // Notificar cambios en las propiedades de pivot para el RenderTransform OnPropertyChanged(nameof(RenderTransformCenterX)); OnPropertyChanged(nameof(RenderTransformCenterY)); } partial void OnPivotCenterYChanged(bool value) { // Notificar cambio de pivot para actualizar objetos conectados OnPropertyChanged(nameof(PivotCenterY)); // Notificar cambios en las propiedades de pivot para el RenderTransform OnPropertyChanged(nameof(RenderTransformCenterX)); OnPropertyChanged(nameof(RenderTransformCenterY)); } public osFramePlate() { Ancho = 0.5f; Alto = 0.5f; Alto_Titulo = 0.2f; Color = Colors.WhiteSmoke; Titulo = "Frame"; Zindex_FramePlate = 0; ShowPlate = true; // Default value } public override void AnchoChanged(float value) { base.AnchoChanged(value); OnPropertyChanged(nameof(RenderTransformCenterX)); } public override void AltoChanged(float value) { base.AltoChanged(value); OnPropertyChanged(nameof(RenderTransformCenterY)); } partial void OnAlto_TituloChanged(float value) { OnPropertyChanged(nameof(RenderTransformCenterY)); } public override void ucLoaded() { base.ucLoaded(); // El UserControl se ha cargado OnEncoder_XChanged(Encoder_X); OnEncoder_YChanged(Encoder_Y); OnEncoder_RotationChanged(Encoder_Rotation); UpdateZIndex(Zindex_FramePlate); } public override void ucUnLoaded() { base.ucUnLoaded(); // El UserControl se esta eliminando // eliminar el objeto de simulacion } /// /// Calcula el punto de pivot basado en los checkboxes PivotCenterX y PivotCenterY /// /// Punto de pivot en coordenadas absolutas public (float X, float Y) GetPivotPoint() { float pivotX = Left + (PivotCenterX ? Ancho / 2 : 0); float pivotY = Top + (PivotCenterY ? Alto / 2 : 0); return (pivotX, pivotY); } /// /// Centro X para el RenderTransform en píxeles del control /// [JsonIgnore] public double RenderTransformCenterX { get { if (PivotCenterX) { // Centro horizontal del rectángulo principal return PixelToMeter.Instance.calc.MetersToPixels(Ancho) / 2.0; } else { // Left del rectángulo principal (0) return 0.0; } } } /// /// Centro Y para el RenderTransform en píxeles del control /// [JsonIgnore] public double RenderTransformCenterY { get { // Altura del título y del rectángulo principal double titleHeight = PixelToMeter.Instance.calc.MetersToPixels(Alto_Titulo); double frameHeight = PixelToMeter.Instance.calc.MetersToPixels(Alto); if (PivotCenterY) { // Centro vertical de todo el control (título + rectángulo) return (titleHeight + frameHeight) / 2.0; } else { // Top absoluto del control (0) return 0.0; } } } } public partial class ucFramePlate : UserControl, IDataContainer { public osBase? Datos { get; set; } public int zIndex_fromFrames { get; set; } public ucFramePlate() { 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.Decorativos; } } }