Compare commits

...

3 Commits

18 changed files with 947 additions and 128 deletions

View File

@ -23,7 +23,7 @@
<xctk:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<TextBox Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
Text="{Binding Value}" />
Text="{Binding Value, UpdateSourceTrigger=LostFocus}" />
</DataTemplate>
</xctk:EditorTemplateDefinition.EditingTemplate>
</xctk:EditorTemplateDefinition>
@ -36,7 +36,7 @@
<xctk:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<xctk:SingleUpDown Increment="0.01"
Text="{Binding Value, Converter={StaticResource floatFormatter}}" />
Text="{Binding Value, Converter={StaticResource floatFormatter}, UpdateSourceTrigger=LostFocus}" />
</DataTemplate>
</xctk:EditorTemplateDefinition.EditingTemplate>
</xctk:EditorTemplateDefinition>
@ -48,7 +48,7 @@
</xctk:EditorTemplateDefinition.TargetProperties>
<xctk:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Value, Converter={StaticResource doubleFormatter}}" />
<TextBox Text="{Binding Value, Converter={StaticResource doubleFormatter}, UpdateSourceTrigger=LostFocus}" />
</DataTemplate>
</xctk:EditorTemplateDefinition.EditingTemplate>
</xctk:EditorTemplateDefinition>

52
Controls/osVisFilter.xaml Normal file
View File

@ -0,0 +1,52 @@
<UserControl x:Class="CtrEditor.Controls.osVisFilter" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:CtrEditor.Controls"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="200">
<UserControl.Resources>
<Style x:Key="FilterCheckBoxStyle" TargetType="CheckBox">
<Setter Property="Margin" Value="0,2,0,2" />
<Setter Property="FontSize" Value="12" />
</Style>
<Style x:Key="FilterHeaderStyle" TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="0,5,0,2" />
</Style>
<Style x:Key="FilterSeparatorStyle" TargetType="Separator">
<Setter Property="Margin" Value="0,5,0,5" />
</Style>
</UserControl.Resources>
<Border BorderBrush="LightGray" BorderThickness="1" Padding="5">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- Fixed Filter Options -->
<TextBlock Text="Filter Options" Style="{StaticResource FilterHeaderStyle}" />
<CheckBox Content="All" IsChecked="{Binding ShowAll, Mode=TwoWay}"
Style="{StaticResource FilterCheckBoxStyle}" />
<CheckBox Content="Cloned" IsChecked="{Binding ShowCloned, Mode=TwoWay}"
Style="{StaticResource FilterCheckBoxStyle}" />
<CheckBox Content="Auto Created" IsChecked="{Binding ShowAutoCreated, Mode=TwoWay}"
Style="{StaticResource FilterCheckBoxStyle}" />
<CheckBox Content="Enable On All Pages" IsChecked="{Binding ShowEnableOnAllPages, Mode=TwoWay}"
Style="{StaticResource FilterCheckBoxStyle}" />
<CheckBox Content="Show On This Page" IsChecked="{Binding ShowOnThisPage, Mode=TwoWay}"
Style="{StaticResource FilterCheckBoxStyle}" />
<!-- Separator between fixed and dynamic options -->
<Separator Style="{StaticResource FilterSeparatorStyle}" />
<!-- Type Filter Options -->
<TextBlock Text="Object Types" Style="{StaticResource FilterHeaderStyle}" />
<ItemsControl ItemsSource="{Binding TypeFilters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding DisplayName}" IsChecked="{Binding IsSelected, Mode=TwoWay}"
Style="{StaticResource FilterCheckBoxStyle}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</Border>
</UserControl>

View File

@ -0,0 +1,223 @@
using System.Collections.ObjectModel;
using System.ComponentModel; // Add this for PropertyChangedEventHandler and PropertyChangedEventArgs
using System.Reflection;
using System.Text.Json.Serialization;
using System.Windows;
using System.Windows.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.ObjetosSim;
namespace CtrEditor.Controls
{
public class FilterChangedEventArgs : EventArgs
{
public osVisFilterViewModel FilterViewModel { get; private set; }
public FilterChangedEventArgs(osVisFilterViewModel viewModel)
{
FilterViewModel = viewModel;
}
}
/// <summary>
/// Interaction logic for osVisFilter.xaml
/// </summary>
public partial class osVisFilter : UserControl
{
public osVisFilter()
{
InitializeComponent();
DataContext = FilterViewModel = new osVisFilterViewModel { Parent = this }; // Set the Parent property
}
public osVisFilterViewModel FilterViewModel { get; private set; }
public event EventHandler<FilterChangedEventArgs> FilterChanged;
public virtual void OnFilterChanged() // Changed from protected to public
{
FilterChanged?.Invoke(this, new FilterChangedEventArgs(FilterViewModel));
}
/// <summary>
/// Updates the type filters based on the provided types
/// </summary>
public void UpdateAvailableTypes(IEnumerable<Type> types)
{
FilterViewModel.UpdateTypeFilters(types);
}
}
/// <summary>
/// ViewModel for the osVisFilter control
/// </summary>
public partial class osVisFilterViewModel : ObservableObject
{
[ObservableProperty]
private bool showAll = true;
[ObservableProperty]
private bool showCloned;
[ObservableProperty]
private bool showAutoCreated;
[ObservableProperty]
private bool showEnableOnAllPages;
[ObservableProperty]
private bool showOnThisPage;
[ObservableProperty]
private ObservableCollection<TypeFilterItem> typeFilters = new ObservableCollection<TypeFilterItem>();
partial void OnShowAllChanged(bool value)
{
NotifyFilterChanged();
}
partial void OnShowClonedChanged(bool value)
{
NotifyFilterChanged();
}
partial void OnShowAutoCreatedChanged(bool value)
{
NotifyFilterChanged();
}
partial void OnShowEnableOnAllPagesChanged(bool value)
{
NotifyFilterChanged();
}
partial void OnShowOnThisPageChanged(bool value)
{
NotifyFilterChanged();
}
partial void OnTypeFiltersChanged(ObservableCollection<TypeFilterItem> value)
{
if (value != null)
{
foreach (var filter in value)
{
filter.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(TypeFilterItem.IsSelected))
{
NotifyFilterChanged();
}
};
}
}
}
private void NotifyFilterChanged()
{
if (this.Parent is osVisFilter filter)
{
filter.OnFilterChanged();
}
}
[JsonIgnore]
public osVisFilter Parent { get; set; }
public osVisFilterViewModel()
{
// PropertyChanged listeners could be added here if needed
if (this.Parent is osVisFilter filter)
{
filter.OnFilterChanged();
}
}
/// <summary>
/// Updates the type filters based on the provided types
/// </summary>
public void UpdateTypeFilters(IEnumerable<Type> types)
{
// Remove types that are no longer present
var typesToRemove = TypeFilters
.Where(tf => !types.Contains(tf.Type))
.ToList();
foreach (var item in typesToRemove)
{
UnsubscribeFromTypeFilter(item);
TypeFilters.Remove(item);
}
// Add new types that aren't already in the list
foreach (var type in types)
{
if (!TypeFilters.Any(tf => tf.Type == type))
{
var newFilter = new TypeFilterItem(type)
{
DisplayName = GetTypeDisplayName(type),
IsSelected = true
};
SubscribeToTypeFilter(newFilter);
TypeFilters.Add(newFilter);
}
}
}
private void SubscribeToTypeFilter(TypeFilterItem filter)
{
filter.PropertyChanged += TypeFilter_PropertyChanged;
}
private void UnsubscribeFromTypeFilter(TypeFilterItem filter)
{
filter.PropertyChanged -= TypeFilter_PropertyChanged;
}
private void TypeFilter_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(TypeFilterItem.IsSelected))
{
NotifyFilterChanged();
}
}
/// <summary>
/// Gets the display name for a type, using the NombreClase static method if available
/// </summary>
private string GetTypeDisplayName(Type type)
{
var methodInfo = type.GetMethod("NombreClase",
BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
return methodInfo != null ?
methodInfo.Invoke(null, null)?.ToString() :
type.Name;
}
}
/// <summary>
/// Represents a type filter item with selection state
/// </summary>
public partial class TypeFilterItem : ObservableObject
{
[ObservableProperty]
private bool isSelected = true;
[ObservableProperty]
private string displayName;
public Type Type { get; }
public TypeFilterItem(Type type)
{
Type = type;
DisplayName = type?.Name ?? "Unknown Type";
}
partial void OnIsSelectedChanged(bool value)
{
OnPropertyChanged(nameof(IsSelected));
}
}
}

View File

@ -22,6 +22,7 @@ using CommunityToolkit.Mvvm.Input;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using CtrEditor.Serialization; // Add this line
using CtrEditor.Controls; // Add this using directive
namespace CtrEditor
{
@ -127,12 +128,14 @@ namespace CtrEditor
{
mainWindow = value;
_objectManager = mainWindow._objectManager; // Initialize _objectManager
// Add the filter changed event handler here instead of in constructor
if (mainWindow.VisFilter != null)
{
mainWindow.VisFilter.FilterChanged += (s, e) => OnVisFilterChanged(e.FilterViewModel);
}
}
}
[ObservableProperty]
public ICollectionView vistaFiltrada;
[ObservableProperty]
private float canvasLeft;
@ -276,13 +279,10 @@ namespace CtrEditor
habilitarEliminarUserControl = false;
}
[ObservableProperty]
public ObjetosSimulablesFilterTypes osListFilter;
[ObservableProperty]
private TipoSimulable selectedItem;
public ICollectionView ObjetosSimulablesFiltered { get; }
public ICollectionView ObjetosSimulablesAllPages { get; }
[ObservableProperty]
@ -298,14 +298,21 @@ namespace CtrEditor
partial void OnObjetosSimulablesChanged(ObservableCollection<osBase> value)
{
VistaFiltrada = CollectionViewSource.GetDefaultView(ObjetosSimulables);
VistaFiltrada.Filter = FiltrarObjetos;
ObjetosSimulables.CollectionChanged += (s, e) =>
if (value != null)
{
VistaFiltrada.Refresh();
if (!inhibitSaveChangesControl && e.Action != NotifyCollectionChangedAction.Move)
HasUnsavedChanges = true;
};
value.CollectionChanged += ObjetosSimulables_CollectionChanged;
UpdateVisFilterTypes();
}
}
private void ObjetosSimulables_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
UpdateVisFilterTypes();
}
private void UpdateVisFilterTypes()
{
MainWindow?.VisFilter?.UpdateAvailableTypes(ObjetosSimulables.Select(o => o.GetType()).Distinct());
}
//
@ -319,10 +326,8 @@ namespace CtrEditor
OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory);
datosDeTrabajo = new DatosDeTrabajo();
OsListFilter = new ObjetosSimulablesFilterTypes();
OsListFilter.All = true;
osListFilter.PropertyChanged += OsListFilter_PropertyChanged;
// Initialize ObjetosSimulables first
ObjetosSimulables = new ObservableCollection<osBase>();
ObjetosSimulables = new ObservableCollection<osBase>();
@ -382,20 +387,61 @@ namespace CtrEditor
_stateSerializer = new StateSerializer(this, datosDeTrabajo, simulationManager);
}
private void OsListFilter_PropertyChanged(object? sender, PropertyChangedEventArgs e)
private void OnVisFilterChanged(osVisFilterViewModel filter) // Changed signature to accept viewmodel directly
{
VistaFiltrada.Refresh();
foreach (var obj in ObjetosSimulables)
{
bool isVisible = true;
// Apply Show All filter
if (!filter.ShowAll)
{
// Check type filter
var typeFilter = filter.TypeFilters.FirstOrDefault(tf => tf.Type == obj.GetType());
if (typeFilter == null || !typeFilter.IsSelected)
{
isVisible = false;
}
// Check other filters
if (filter.ShowCloned && !obj.Cloned)
isVisible = false;
if (filter.ShowAutoCreated && !obj.AutoCreated)
isVisible = false;
if (filter.ShowEnableOnAllPages && !obj.Enable_On_All_Pages)
isVisible = false;
if (filter.ShowOnThisPage && !obj.Show_On_This_Page)
isVisible = false;
}
obj.IsVisFilter = isVisible;
// Update Canvas object visibility
if (obj.VisualRepresentation != null)
{
obj.VisualRepresentation.Visibility = isVisible ? Visibility.Visible : Visibility.Collapsed;
}
}
}
private bool FiltrarObjetos(object item)
public void LoadStateObjetosSimulables()
{
var objeto = item as osBase;
return osListFilter.All || (objeto.Cloned == osListFilter.Cloned) &&
(objeto.Enable_On_All_Pages == osListFilter.Enable_On_All_Pages) &&
(objeto.Show_On_This_Page == osListFilter.Show_On_This_Page);
if (SelectedImage != null)
{
_stateSerializer.LoadState(SelectedImage);
// Aplicar los filtros actuales a los objetos recién cargados
if (MainWindow?.VisFilter?.FilterViewModel != null)
{
OnVisFilterChanged(MainWindow.VisFilter.FilterViewModel);
}
}
}
public void LoadInitialData()
{
// Suponiendo que "SelectedImage" es una propiedad que al establecerse dispara "ImageSelected"
@ -838,14 +884,6 @@ namespace CtrEditor
}
}
public void LoadStateObjetosSimulables()
{
if (SelectedImage != null)
{
_stateSerializer.LoadState(SelectedImage);
}
}
// Se cargan los datos de cada UserControl en el StackPanel
public void CargarPropiedadesosDatos(osBase selectedObject, Controls.PanelEdicionControl PanelEdicion, ResourceDictionary Resources)
{

View File

@ -217,19 +217,12 @@
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" MinHeight="50" />
<!-- ListBox1 -->
<RowDefinition Height="*" MinHeight="50" />
<!-- GridSplitter -->
<RowDefinition Height="Auto" />
<!-- Tree -->
<RowDefinition Height="*" MinHeight="100" />
<!-- GridSplitter -->
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" MinHeight="200" />
<!-- StackPanel -->
<RowDefinition Height="Auto" />
<!-- ToolBarTray -->
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ToolBarTray Grid.Row="0">
@ -261,47 +254,65 @@
</ToolBar>
</ToolBarTray>
<xctk:PropertyGrid Grid.Row="1" x:Name="PanelFilter" AutoGenerateProperties="True"
ShowDescriptionByTooltip="False" ShowSearchBox="False" ShowSortOptions="False"
ShowSummary="False" ShowTitle="False" SelectedObject="{Binding OsListFilter}">
</xctk:PropertyGrid>
<!-- Filter Control -->
<Expander Grid.Row="1" Header="Filters" IsExpanded="False">
<controls:osVisFilter x:Name="VisFilter" Margin="5"/>
</Expander>
<!-- ListBox -->
<ListBox x:Name="ListaOs" Grid.Row="2" Margin="5" ItemsSource="{Binding VistaFiltrada}"
SelectedItem="{Binding SelectedItemOsList, Mode=TwoWay}"
SelectionChanged="ListaOs_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Nombre}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Enable_On_All_Pages}" Value="True">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Enable_On_All_Pages}" Value="False">
<Setter Property="Foreground" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Expander Grid.Row="2" Header="Objects List" IsExpanded="False">
<ListBox x:Name="ListaOs"
Margin="5"
MinHeight="100"
MaxHeight="300"
ItemsSource="{Binding ObjetosSimulables}"
SelectedItem="{Binding SelectedItemOsList, Mode=TwoWay}"
SelectionChanged="ListaOs_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Nombre}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Enable_On_All_Pages}" Value="True">
<Setter Property="Foreground" Value="Blue" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Enable_On_All_Pages}" Value="False">
<Setter Property="Foreground" Value="Black" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsVisFilter}" Value="False">
<Setter Property="Opacity" Value="0.5" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
<!-- Object Hierarchy -->
<Expander Grid.Row="3" Header="Object Hierarchy" IsExpanded="True">
<controls:ObjectHierarchyView x:Name="ObjectHierarchy"
Margin="5"
MinHeight="100"
MaxHeight="300"/>
</Expander>
<!-- GridSplitter -->
<GridSplitter Grid.Row="3" Height="5" HorizontalAlignment="Stretch" Background="Gray"
ResizeDirection="Rows" VerticalAlignment="Center" />
<controls:ObjectHierarchyView x:Name="ObjectHierarchy" Grid.Row="4" Margin="5" />
<!-- GridSplitter -->
<GridSplitter Grid.Row="5" Height="5" HorizontalAlignment="Stretch" Background="Gray"
ResizeDirection="Rows" VerticalAlignment="Center" />
<GridSplitter Grid.Row="4" Height="5"
HorizontalAlignment="Stretch"
Background="Gray"
ResizeDirection="Rows"
VerticalAlignment="Center" />
<!-- PanelEdicion -->
<controls:PanelEdicionControl Grid.Row="6"
x:Name="PanelEdicion"
Margin="5"/>
<controls:PanelEdicionControl Grid.Row="5"
x:Name="PanelEdicion"
Margin="5"/>
<ToolBarTray Grid.Row="7">
<ToolBarTray Grid.Row="6">
<ToolBar>
<Button Command="{Binding TBEliminarUserControlCommand}" ToolTip="Eliminar Control">
<StackPanel>

View File

@ -221,7 +221,7 @@ namespace CtrEditor
foreach (var obj in selectedObjects)
{
if (obj.VisualRepresentation != null && obj.Show_On_This_Page)
if (obj.VisualRepresentation != null)
{
// Obtener el bounding box del objeto actual
Rect objectBounds = VisualTreeHelper.GetDescendantBounds(obj.VisualRepresentation);
@ -244,6 +244,12 @@ namespace CtrEditor
private Rectangle CreateSelectionRectangle(FuncionesBase.MutableRect rectBox, double rectHighlightSize)
{
if (double.IsInfinity(rectBox.Width) || double.IsInfinity(rectBox.Height) ||
double.IsNaN(rectBox.Width) || double.IsNaN(rectBox.Height))
{
throw new ArgumentException("Invalid dimensions for selection rectangle.");
}
var rect = new Rectangle
{
Width = rectBox.Width + (rectHighlightSize * 2),
@ -263,6 +269,7 @@ namespace CtrEditor
return rect;
}
private void AddResizeHandles(FuncionesBase.MutableRect rectBox, double defaultRectSize,
Cursor rotationCursorRx, Cursor rotationCursorSx)
{
@ -403,18 +410,26 @@ namespace CtrEditor
public void SelectObject(osBase obj)
{
if (!_selectedObjects.Contains(obj))
if (_mainWindow.DataContext is MainViewModel vm)
{
_selectedObjects.Add(obj);
obj.IsSelected = true;
// Agregar highlight visual solo si estamos en modo multi-selección
if (_mainWindow.DataContext is MainViewModel vm && vm.IsMultiSelectionActive)
// Add new object if not already selected
if (!_selectedObjects.Contains(obj))
{
AddSelectionHighlight(obj.VisualRepresentation);
}
// If not in multi-selection mode, clear existing selection first
if (!vm.IsMultiSelectionActive)
ClearSelection();
UpdateSelectionVisuals();
_selectedObjects.Add(obj);
obj.IsSelected = true;
// Add highlight visual only if in multi-selection mode
if (vm.IsMultiSelectionActive)
{
AddSelectionHighlight(obj.VisualRepresentation);
}
UpdateSelectionVisuals();
}
}
}

View File

@ -56,7 +56,7 @@ namespace CtrEditor.ObjetosSim
[ObservableProperty]
public float alto_Titulo;
// Encoder
// Encoder X
[ObservableProperty]
[property: Description("This is a link to a Encoder for X.")]
[property: Category("Encoders:")]
@ -73,6 +73,33 @@ namespace CtrEditor.ObjetosSim
[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<osEncoderMotorLineal>))]
private string encoder_Y;
[ObservableProperty]
[property: Description("K Pulses per meter for Moving")]
[property: Category("Encoders:")]
public float k_encoder_Y;
[ObservableProperty]
[property: Description("Y in meter offset Top. Position when the encoder is 0")]
[property: Category("Encoders:")]
public float offset_encoder_Y;
partial void OnK_encoder_YChanged(float value)
{
UpdatePosition();
}
partial void OnOffset_encoder_YChanged(float value)
{
UpdatePosition();
}
partial void OnK_encoder_XChanged(float value)
{
UpdatePosition();
@ -86,9 +113,15 @@ namespace CtrEditor.ObjetosSim
[JsonIgnore]
private osEncoderMotorLineal EncoderX;
[JsonIgnore]
private osEncoderMotorLineal EncoderY;
[JsonIgnore]
private bool isUpdatingFromEncoderX = false;
[JsonIgnore]
private bool isUpdatingFromEncoderY = false;
partial void OnEncoder_XChanged(string value)
{
if (EncoderX != null)
@ -101,6 +134,18 @@ namespace CtrEditor.ObjetosSim
}
}
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;
}
}
private void OnEncoderXPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (!isUpdatingFromEncoderX)
@ -108,7 +153,7 @@ namespace CtrEditor.ObjetosSim
isUpdatingFromEncoderX = true;
// Actualizamos el nombre si este fue modificado
if (e.PropertyName == nameof(osEncoderMotorLineal.Nombre))
Group_Panel = ((osEncoderMotorLineal)sender).Nombre;
Encoder_X = ((osEncoderMotorLineal)sender).Nombre;
if (e.PropertyName == nameof(osEncoderMotorLineal.Valor_Actual))
{
@ -119,13 +164,33 @@ namespace CtrEditor.ObjetosSim
}
}
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;
}
}
public void UpdatePosition()
{
if (EncoderX == null)
return;
if (K_encoder_X == 0)
return;
Left = (EncoderX.Valor_Actual / k_encoder_X) + offset_encoder_X;
// Update X position if encoder is available
if (EncoderX != null && K_encoder_X != 0)
Left = (EncoderX.Valor_Actual / k_encoder_X) + offset_encoder_X;
// Update Y position if encoder is available
if (EncoderY != null && K_encoder_Y != 0)
Top = (EncoderY.Valor_Actual / k_encoder_Y) + offset_encoder_Y;
}
public override void TopChanging(float oldValue, float newValue)
@ -158,6 +223,7 @@ namespace CtrEditor.ObjetosSim
base.ucLoaded();
// El UserControl se ha cargado
OnEncoder_XChanged(Encoder_X);
OnEncoder_YChanged(Encoder_Y);
UpdateZIndex(Zindex_FramePlate);
}

View File

@ -58,9 +58,32 @@ namespace CtrEditor.ObjetosSim
[ObservableProperty]
private float radioExterno;
partial void OnRadioExternoChanged(float value)
{
// Update ancho and alto based on radioExterno
Ancho = value * 2;
Alto = value * 2;
// Ensure radioInterno maintains proper proportion if needed
if (RadioInterno >= value)
{
RadioInterno = value * 0.75f; // Default proportion
}
ActualizarGeometrias();
}
[ObservableProperty]
private float radioInterno;
[ObservableProperty]
[property: Description("Bit to enable Link to Motor")]
[property: Category("PLC link:")]
string tag_ReleActivatedMotor;
[ObservableProperty]
[property: Description("Link to Motor")]
[property: Category("PLC link:")]
@ -130,11 +153,52 @@ namespace CtrEditor.ObjetosSim
[ObservableProperty]
public bool esMarcha;
public override void OnResize(float Delta_Width, float Delta_Height)
{
// Calculate the proportional change factor
float widthChangeFactor = (Ancho + Delta_Width) / Ancho;
float heightChangeFactor = (Alto + Delta_Height) / Alto;
// Use the average or minimum change factor to maintain aspect ratio
float changeFactor = Math.Min(widthChangeFactor, heightChangeFactor);
// Save the original radiuses for calculating position adjustments
float originalRadioExterno = RadioExterno;
// Apply the change factor to both radios
RadioExterno *= changeFactor;
RadioInterno *= changeFactor;
// Calculate position adjustment to keep the component centered
float radiusDifference = RadioExterno - originalRadioExterno;
// Adjust Left and Top to maintain center position
// We move by negative half the difference because the component expands outward
Left -= radiusDifference;
Top -= radiusDifference;
// Ensure minimums
if (RadioExterno < 0.1f)
RadioExterno = 0.1f;
if (RadioInterno < 0.05f)
RadioInterno = 0.05f;
// Ensure radioInterno is always less than radioExterno
if (RadioInterno >= RadioExterno)
RadioInterno = RadioExterno * 0.75f;
}
public osTransporteCurva()
{
RadioExterno = 1.3f;
RadioInterno = 1;
RadioInterno = 1f;
Ancho = RadioExterno * 2; // Set initial width based on external radius
Alto = RadioExterno * 2; // Set initial height based on external radius
Arco_en_grados = 90;
Tag_ReleActivatedMotor = "1";
}
public override void UpdateGeometryStart()
@ -149,7 +213,10 @@ namespace CtrEditor.ObjetosSim
if (Motor != null)
{
if (Motor is osVMmotorSim motor)
VelocidadActual = motor.Velocidad;
if (LeerBitTag(Tag_ReleActivatedMotor))
VelocidadActual = motor.Velocidad;
else
VelocidadActual = 0;
}
}

View File

@ -69,6 +69,11 @@ namespace CtrEditor.ObjetosSim
[ObservableProperty]
Color color = Colors.Blue;
[ObservableProperty]
[property: Description("Bit to enable Link to Motor")]
[property: Category("PLC link:")]
string tag_ReleActivatedMotor;
[ObservableProperty]
[property: Description("Link to Motor")]
[property: Category("PLC link:")]
@ -152,6 +157,7 @@ namespace CtrEditor.ObjetosSim
Alto = 0.10f;
AltoGuia = 0.03f;
Distance = 0.01f;
Tag_ReleActivatedMotor = "1";
}
public override void UpdateGeometryStart()
@ -159,16 +165,21 @@ namespace CtrEditor.ObjetosSim
// Se llama antes de la simulacion
ActualizarGeometrias();
}
public override void SimulationStop()
{
// Se llama al detener la simulacion
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
{
if (Motor != null)
if (Motor is osVMmotorSim id_motor)
VelocidadActual = id_motor.Velocidad;
if (LeerBitTag(Tag_ReleActivatedMotor))
VelocidadActual = id_motor.Velocidad;
else
VelocidadActual = 0;
}
public override void ucLoaded()

View File

@ -41,6 +41,11 @@ namespace CtrEditor.ObjetosSim
[ObservableProperty]
Color color;
[ObservableProperty]
[property: Description("Bit to enable Link to Motor")]
[property: Category("PLC link:")]
string tag_ReleActivatedMotor;
[ObservableProperty]
[property: Description("Link to Motor A")]
[property: Category("PLC link:")]
@ -245,6 +250,7 @@ namespace CtrEditor.ObjetosSim
Storyboards = new Dictionary<Rectangle, Storyboard>();
TransportsDirection = new Dictionary<Rectangle, BoolReference>();
TransportsVelocidad = new Dictionary<Rectangle, FloatReference>();
Tag_ReleActivatedMotor = "1";
}
public override void UpdateGeometryStart()
@ -268,13 +274,19 @@ namespace CtrEditor.ObjetosSim
if (_osMotorA != null)
{
if (_osMotorA is osVMmotorSim motor)
VelocidadActualA = motor.Velocidad;
if (LeerBitTag(Tag_ReleActivatedMotor))
VelocidadActualA = motor.Velocidad;
else
VelocidadActualA = 0;
}
if (_osMotorB != null)
{
if (_osMotorB is osVMmotorSim motor)
VelocidadActualB = motor.Velocidad;
if (LeerBitTag(Tag_ReleActivatedMotor))
VelocidadActualB = motor.Velocidad;
else
VelocidadActualB = 0;
}
}

View File

@ -66,6 +66,11 @@ namespace CtrEditor.ObjetosSim
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
[ObservableProperty]
[property: Description("Bit to enable Link to Motor")]
[property: Category("PLC link:")]
string tag_ReleActivatedMotor;
[ObservableProperty]
[property: Description("Link to Motor")]
[property: Category("PLC link:")]
@ -131,6 +136,7 @@ namespace CtrEditor.ObjetosSim
{
Ancho = 1;
Alto = 0.10f;
Tag_ReleActivatedMotor = "1";
}
public override void SimulationStop()
@ -148,7 +154,10 @@ namespace CtrEditor.ObjetosSim
{
if (Motor != null)
if (Motor is osVMmotorSim motor)
VelocidadActual = motor.Velocidad;
if (LeerBitTag(Tag_ReleActivatedMotor))
VelocidadActual = motor.Velocidad;
else
VelocidadActual = 0;
}
public override void ucLoaded()

View File

@ -0,0 +1,50 @@
<UserControl x:Class="CtrEditor.ObjetosSim.ucTransporteTTopDualInverter"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors" xmlns:vm="clr-namespace:CtrEditor.ObjetosSim"
mc:Ignorable="d">
<UserControl.Resources>
<!-- Define the VisualBrush for the conveyor belt pattern -->
<VisualBrush x:Key="BeltBrush" TileMode="Tile" Viewport="0,0,20,10" ViewportUnits="Absolute" Viewbox="0,0,20,10"
ViewboxUnits="Absolute">
<VisualBrush.Transform>
<TransformGroup>
<TranslateTransform />
</TransformGroup>
</VisualBrush.Transform>
<VisualBrush.Visual>
<Canvas>
<Rectangle Fill="LightGray" Width="10" Height="10" />
<Rectangle Fill="GhostWhite" Width="10" Height="10" Canvas.Left="10" />
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</UserControl.Resources>
<UserControl.DataContext>
<vm:osTransporteTTop Ancho="2" />
</UserControl.DataContext>
<Canvas RenderTransformOrigin="0,0">
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform Angle="{Binding Angulo}" />
<TranslateTransform />
</TransformGroup>
</Canvas.RenderTransform>
<Rectangle x:Name="Transporte" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}"
Fill="{StaticResource BeltBrush}">
</Rectangle>
<Viewbox Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}"
Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Stretch="Uniform">
<Label Content="{Binding Nombre}" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold"
FontSize="18" Opacity="0.9" />
</Viewbox>
</Canvas>
</UserControl>

View File

@ -0,0 +1,267 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CtrEditor.FuncionesBase;
using System.Windows;
using System.Windows.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using LibS7Adv;
using CtrEditor.Simulacion;
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using System.ComponentModel;
using CtrEditor.FuncionesBase;
using System.Text.Json.Serialization;
namespace CtrEditor.ObjetosSim
{
/// <summary>
/// Interaction logic for ucTransporteTTop.xaml
/// </summary>
///
public partial class osTransporteTTopDualInverter : osBase, IosBase
{
private simTransporte SimGeometria;
private osVMmotorSim MotorA;
private osVMmotorSim MotorB;
public static string NombreClase()
{
return "Transporte Dual Inverter";
}
private string nombre = "Transporte TTOP Dual Inverter";
[property: Category("Id:")]
public override string Nombre
{
get => nombre;
set => SetProperty(ref nombre, value);
}
[ObservableProperty]
[property: Category("Simulation:")]
public float velocidadActual;
partial void OnVelocidadActualChanged(float value)
{
SetSpeed();
}
[ObservableProperty]
[property: Category("Simulation:")]
bool invertirDireccion;
partial void OnInvertirDireccionChanged(bool value)
{
SetSpeed();
if (_visualRepresentation is ucTransporteTTop uc)
{
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
}
void SetSpeed()
{
if (InvertirDireccion)
SimGeometria?.SetSpeed(-VelocidadActual);
else
SimGeometria?.SetSpeed(VelocidadActual);
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
[ObservableProperty]
[property: Description("Bit to enable Link to Inverter A")]
[property: Category("PLC link:")]
string tag_ReleActivatedMotor_A;
[ObservableProperty]
[property: Description("Bit to enable Link to Inverter B")]
[property: Category("PLC link:")]
string tag_ReleActivatedMotor_B;
[ObservableProperty]
[property: Description("Link to Inverter A")]
[property: Category("PLC link:")]
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
string id_Motor_A;
[ObservableProperty]
[property: Description("Link to Inverter B")]
[property: Category("PLC link:")]
[property: ItemsSource(typeof(osBaseItemsSource<osVMmotorSim>))]
string id_Motor_B;
[JsonIgnore]
private PropertyChangedEventHandler motorPropertyChangedHandler;
partial void OnId_Motor_AChanged(string value)
{
if (MotorA != null && motorPropertyChangedHandler != null)
MotorA.PropertyChanged -= motorPropertyChangedHandler;
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
{
MotorA = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
if (MotorA != null)
{
motorPropertyChangedHandler = (sender, e) =>
{
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
{
Id_Motor_A = ((osVMmotorSim)sender).Nombre;
}
};
MotorA.PropertyChanged += motorPropertyChangedHandler;
}
}
}
partial void OnId_Motor_BChanged(string value)
{
if (MotorB != null && motorPropertyChangedHandler != null)
MotorB.PropertyChanged -= motorPropertyChangedHandler;
if (_mainViewModel != null && !string.IsNullOrEmpty(value))
{
MotorB = (osVMmotorSim)_mainViewModel.ObjetosSimulables.FirstOrDefault(s => s is osVMmotorSim motor && motor.Nombre == value);
if (MotorB != null)
{
motorPropertyChangedHandler = (sender, e) =>
{
if (e.PropertyName == nameof(osVMmotorSim.Nombre))
{
Id_Motor_B = ((osVMmotorSim)sender).Nombre;
}
};
MotorB.PropertyChanged += motorPropertyChangedHandler;
}
}
}
[ObservableProperty]
[property: Category("Setup:")]
public float frictionCoefficient;
[ObservableProperty]
[property: Category("Setup:")]
public float velMax50hz;
[ObservableProperty]
[property: Category("Setup:")]
public float tiempoRampa;
[ObservableProperty]
[property: Category("Setup:")]
public bool esMarcha;
private void ActualizarGeometrias()
{
if (_visualRepresentation is ucTransporteTTop uc)
{
UpdateRectangle(SimGeometria, uc.Transporte, Alto, Ancho, Angulo);
SetSpeed();
}
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
public override void OnMoveResizeRotate()
{
ActualizarGeometrias();
}
public osTransporteTTopDualInverter()
{
Ancho = 1;
Alto = 0.10f;
Tag_ReleActivatedMotor_A = "1";
Tag_ReleActivatedMotor_B = "1";
}
public override void SimulationStop()
{
// Se llama al detener la simulacion
ActualizarAnimacionStoryBoardTransporte(VelocidadActual);
}
public override void UpdateGeometryStart()
{
// Se llama antes de la simulacion
ActualizarGeometrias();
}
public override void UpdatePLC(PLCViewModel plc, int elapsedMilliseconds)
{
if (LeerBitTag(Tag_ReleActivatedMotor_A))
{
if (MotorA != null)
if (MotorA is osVMmotorSim motor)
VelocidadActual = motor.Velocidad;
else
VelocidadActual = 0;
}
else if (LeerBitTag(Tag_ReleActivatedMotor_B))
{
if (MotorB != null)
if (MotorB is osVMmotorSim motor)
VelocidadActual = motor.Velocidad;
else
VelocidadActual = 0;
}
}
public override void ucLoaded()
{
// El UserControl ya se ha cargado y podemos obtener las coordenadas para
// crear el objeto de simulacion
base.ucLoaded();
OnId_Motor_AChanged(Id_Motor_A); // Link Id_Motor = Motor
OnId_Motor_BChanged(Id_Motor_B); // Link Id_Motor = Motor
if (_visualRepresentation is ucTransporteTTop uc)
{
SimGeometria = AddRectangle(simulationManager, uc.Transporte, Alto, Ancho, Angulo);
CrearAnimacionStoryBoardTrasnporte(uc.Transporte, InvertirDireccion);
}
}
public override void ucUnLoaded()
{
// El UserControl se esta eliminando
// eliminar el objeto de simulacion
simulationManager.Remove(SimGeometria);
}
}
public partial class ucTransporteTTopDualInverter : UserControl, IDataContainer
{
public osBase? Datos { get; set; }
public int zIndex_fromFrames { get; set; }
public ucTransporteTTopDualInverter()
{
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;
}
}
}

View File

@ -160,6 +160,7 @@ namespace CtrEditor.ObjetosSim.Extraccion_Datos
Opacity_oculto = 0.1f;
Idioma_Extraccion = Idiomas.DEFAULT_LANGUAGE;
Pattern_Type = TagPattern.DEFAULT_PATTERN;
Eliminar_enters = true;
}
public void CaptureImageAreaAndDoOCR()

View File

@ -94,8 +94,9 @@ namespace CtrEditor.ObjetosSim
}
public static void CargarPropiedadesosDatos(object selectedObject, PropertyGrid propertyGrid)
public static void CargarPropiedadesosDatos(osBase selectedObject, PropertyGrid propertyGrid)
{
// Limpia las propiedades previas
propertyGrid.SelectedObject = null;
propertyGrid.PropertyDefinitions.Clear();

View File

@ -69,6 +69,11 @@ namespace CtrEditor.ObjetosSim
[JsonIgnore]
private System.Threading.Timer timer = null;
[JsonIgnore]
[ObservableProperty]
[property: Hidden]
public bool isVisFilter;
public UniqueId Id { get; set; }
[ObservableProperty]
@ -402,12 +407,16 @@ namespace CtrEditor.ObjetosSim
msResized.Seek(0, SeekOrigin.Begin);
using (var img = Pix.LoadFromMemory(msResized.ToArray()))
using (var engine = new TesseractEngine(@"./Tesseract", "eng", EngineMode.Default))
{
// Configuraciones para mejorar el OCR de una sola letra
engine.SetVariable("tessedit_char_whitelist", " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-."); // Lista blanca de caracteres
var result = engine.Process(img);
return result.GetText();
// Use AppDomain.CurrentDomain.BaseDirectory to ensure we find Tesseract in the application directory
string tesseractPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tesseract");
using (var engine = new TesseractEngine(tesseractPath, "eng", EngineMode.Default))
{
// Configuraciones para mejorar el OCR de una sola letra
engine.SetVariable("tessedit_char_whitelist", " ABCDEFGHIJKLMNÑOPQRSTUVWXYZabcdefghijklmnñopqrstuvwxyz0123456789-."); // Lista blanca de caracteres
var result = engine.Process(img);
return result.GetText();
}
}
}
}
@ -510,6 +519,8 @@ namespace CtrEditor.ObjetosSim
UniqueId cloned_from;
[ObservableProperty]
[JsonIgnore]
[property: Hidden]
private bool isSelected;
private async void TimerCallback(object state)

View File

@ -17,19 +17,6 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace CtrEditor
{
public partial class ObjetosSimulablesFilterTypes : ObservableObject
{
[ObservableProperty]
public bool cloned;
[ObservableProperty]
public bool enable_On_All_Pages;
[ObservableProperty]
public bool show_On_This_Page;
[ObservableProperty]
public bool all;
}
public class ConnectStateToBtnTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

View File

@ -36,8 +36,6 @@ namespace CtrEditor
private string _imagen;
private int _id;
public ObjetosSimulablesFilterTypes osListFilter;
public List<string> RecentDirectories { get; set; } = new List<string>();
public List<ColumnLanguageMapping> ColumnLanguages { get; set; } = new List<ColumnLanguageMapping>();