mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 21:38:38 +00:00
UI - Replaced tuples with custom classes for binding
As far as i know, it's not possible to have CompiledBindings with tuples, since tuple values are fields and not properties. This change allows for compiled bindings, and makes the intent behind the tuples clearer
This commit is contained in:
parent
59f9479d9a
commit
5429346396
@ -3,11 +3,12 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Shared"
|
||||
x:Class="Artemis.UI.Shared.EnumComboBox">
|
||||
<ComboBox x:Name="ChildEnumComboBox" HorizontalAlignment="Stretch">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding [1]}" />
|
||||
<DataTemplate x:DataType="local:EnumComboBoxItem">
|
||||
<TextBlock Text="{CompiledBinding Value}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
@ -20,11 +20,9 @@ public partial class EnumComboBox : UserControl
|
||||
/// </summary>
|
||||
public static readonly StyledProperty<object?> ValueProperty = AvaloniaProperty.Register<EnumComboBox, object?>(nameof(Value), defaultBindingMode: BindingMode.TwoWay);
|
||||
|
||||
private readonly ObservableCollection<(Enum, string)> _currentValues = new();
|
||||
private readonly ObservableCollection<EnumComboBoxItem> _currentValues = new();
|
||||
private Type? _currentType;
|
||||
|
||||
private ComboBox? _enumComboBox;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="EnumComboBox" /> class.
|
||||
/// </summary>
|
||||
@ -54,35 +52,35 @@ public partial class EnumComboBox : UserControl
|
||||
|
||||
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (_enumComboBox == null || _enumComboBox.SelectedIndex == -1)
|
||||
if (ChildEnumComboBox == null || ChildEnumComboBox.SelectedIndex == -1)
|
||||
return;
|
||||
|
||||
(Enum enumValue, _) = _currentValues[_enumComboBox.SelectedIndex];
|
||||
if (!Equals(Value, enumValue))
|
||||
Value = enumValue;
|
||||
EnumComboBoxItem v = _currentValues[ChildEnumComboBox.SelectedIndex];
|
||||
if (!Equals(Value, v.Value))
|
||||
Value = v.Value;
|
||||
}
|
||||
|
||||
private void UpdateValues()
|
||||
{
|
||||
Type? newType = Value?.GetType();
|
||||
if (_enumComboBox == null || newType == null || _currentType == newType)
|
||||
if (ChildEnumComboBox == null || newType == null || _currentType == newType)
|
||||
return;
|
||||
|
||||
_currentValues.Clear();
|
||||
foreach ((Enum, string) valueDesc in EnumUtilities.GetAllValuesAndDescriptions(newType))
|
||||
_currentValues.Add(valueDesc);
|
||||
_currentValues.Add(new EnumComboBoxItem(value: valueDesc.Item1, description: valueDesc.Item2));
|
||||
|
||||
_currentType = newType;
|
||||
}
|
||||
|
||||
private void UpdateSelection()
|
||||
{
|
||||
if (_enumComboBox == null || Value is not Enum)
|
||||
if (ChildEnumComboBox == null || Value is not Enum)
|
||||
return;
|
||||
|
||||
(Enum, string) value = _currentValues.FirstOrDefault(v => v.Item1.Equals(Value));
|
||||
if (!Equals(value.Item1, _enumComboBox.SelectedItem))
|
||||
_enumComboBox.SelectedItem = value;
|
||||
EnumComboBoxItem? value = _currentValues.FirstOrDefault(v => v.Value.Equals(Value));
|
||||
if (!Equals(value?.Value, ChildEnumComboBox.SelectedItem))
|
||||
ChildEnumComboBox.SelectedItem = value;
|
||||
}
|
||||
|
||||
#region Overrides of TemplatedControl
|
||||
@ -90,12 +88,11 @@ public partial class EnumComboBox : UserControl
|
||||
/// <inheritdoc />
|
||||
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
_enumComboBox = this.Get<ComboBox>("ChildEnumComboBox");
|
||||
_enumComboBox.ItemsSource = _currentValues;
|
||||
ChildEnumComboBox.ItemsSource = _currentValues;
|
||||
|
||||
UpdateValues();
|
||||
UpdateSelection();
|
||||
_enumComboBox.SelectionChanged += OnSelectionChanged;
|
||||
ChildEnumComboBox.SelectionChanged += OnSelectionChanged;
|
||||
|
||||
base.OnAttachedToLogicalTree(e);
|
||||
}
|
||||
@ -103,11 +100,36 @@ public partial class EnumComboBox : UserControl
|
||||
/// <inheritdoc />
|
||||
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
|
||||
{
|
||||
if (_enumComboBox != null)
|
||||
_enumComboBox.SelectionChanged -= OnSelectionChanged;
|
||||
if (ChildEnumComboBox != null)
|
||||
ChildEnumComboBox.SelectionChanged -= OnSelectionChanged;
|
||||
|
||||
base.OnDetachedFromLogicalTree(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an item in the <see cref="EnumComboBox" />
|
||||
/// </summary>
|
||||
public class EnumComboBoxItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="EnumComboBoxItem" /> class.
|
||||
/// </summary>
|
||||
public EnumComboBoxItem(Enum value, string description)
|
||||
{
|
||||
Value = value;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the item
|
||||
/// </summary>
|
||||
public Enum Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the description of the item
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
}
|
||||
@ -48,8 +48,8 @@
|
||||
AutoGenerateColumns="False"
|
||||
Margin="10">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Binding="{Binding [0].RgbLed.Id}" Header="Original LED ID" Width="*" />
|
||||
<DataGridTextColumn Binding="{Binding [1].RgbLed.Id}" Header="Remapped LED ID" Width="*" />
|
||||
<DataGridTextColumn Binding="{CompiledBinding Path=Original.RgbLed.Id}" Header="Original LED ID" Width="*" />
|
||||
<DataGridTextColumn Binding="{CompiledBinding Path=Replacement.RgbLed.Id}" Header="Remapped LED ID" Width="*" />
|
||||
|
||||
<DataGridTemplateColumn Width="Auto" IsReadOnly="True">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
@ -31,8 +31,8 @@ public class InputMappingsTabViewModel : ActivatableViewModelBase
|
||||
|
||||
Device = device;
|
||||
DisplayName = "Input Mappings";
|
||||
InputMappings = new ObservableCollection<(ArtemisLed, ArtemisLed)>();
|
||||
DeleteMapping = ReactiveCommand.Create<(ArtemisLed, ArtemisLed)>(ExecuteDeleteMapping);
|
||||
InputMappings = new ObservableCollection<ArtemisInputMapping>();
|
||||
DeleteMapping = ReactiveCommand.Create<ArtemisInputMapping>(ExecuteDeleteMapping);
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
@ -48,7 +48,7 @@ public class InputMappingsTabViewModel : ActivatableViewModelBase
|
||||
});
|
||||
}
|
||||
|
||||
public ReactiveCommand<(ArtemisLed, ArtemisLed), Unit> DeleteMapping { get; }
|
||||
public ReactiveCommand<ArtemisInputMapping, Unit> DeleteMapping { get; }
|
||||
|
||||
public ArtemisDevice Device { get; }
|
||||
|
||||
@ -58,11 +58,11 @@ public class InputMappingsTabViewModel : ActivatableViewModelBase
|
||||
set => RaiseAndSetIfChanged(ref _selectedLed, value);
|
||||
}
|
||||
|
||||
public ObservableCollection<(ArtemisLed, ArtemisLed)> InputMappings { get; }
|
||||
public ObservableCollection<ArtemisInputMapping> InputMappings { get; }
|
||||
|
||||
private void ExecuteDeleteMapping((ArtemisLed, ArtemisLed) inputMapping)
|
||||
private void ExecuteDeleteMapping(ArtemisInputMapping inputMapping)
|
||||
{
|
||||
Device.InputMappings.Remove(inputMapping.Item1);
|
||||
Device.InputMappings.Remove(inputMapping.Original);
|
||||
UpdateInputMappings();
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ public class InputMappingsTabViewModel : ActivatableViewModelBase
|
||||
if (InputMappings.Any())
|
||||
InputMappings.Clear();
|
||||
|
||||
foreach ((ArtemisLed, ArtemisLed) tuple in Device.InputMappings.Select(m => (m.Key, m.Value)))
|
||||
foreach (ArtemisInputMapping tuple in Device.InputMappings.Select(m => new ArtemisInputMapping(m.Key, m.Value)))
|
||||
InputMappings.Add(tuple);
|
||||
}
|
||||
|
||||
@ -100,4 +100,29 @@ public class InputMappingsTabViewModel : ActivatableViewModelBase
|
||||
{
|
||||
SelectedLed = _selectedLeds.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a pair of LEDs, the original and the replacement
|
||||
/// </summary>
|
||||
public class ArtemisInputMapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ArtemisInputMapping" /> class
|
||||
/// </summary>
|
||||
public ArtemisInputMapping(ArtemisLed original, ArtemisLed replacement)
|
||||
{
|
||||
Original = original;
|
||||
Replacement = replacement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The original LED
|
||||
/// </summary>
|
||||
public ArtemisLed Original { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The replacement LED
|
||||
/// </summary>
|
||||
public ArtemisLed Replacement { get; set; }
|
||||
}
|
||||
@ -15,7 +15,7 @@
|
||||
BorderBrush="{DynamicResource ButtonBorderBrush}"
|
||||
BorderThickness="0,0,0,1"
|
||||
Height="29">
|
||||
<Grid Margin="{Binding Converter={StaticResource PropertyTreeMarginConverter}}" ColumnDefinitions="Auto,*,Auto,Auto,Auto">
|
||||
<Grid Margin="{CompiledBinding Converter={StaticResource PropertyTreeMarginConverter}}" ColumnDefinitions="Auto,*,Auto,Auto,Auto">
|
||||
<ToggleButton Grid.Column="0"
|
||||
Classes="icon-button"
|
||||
ToolTip.Tip="Toggle key-framing"
|
||||
|
||||
@ -10,7 +10,7 @@ public partial class InputPinView : PinView
|
||||
public InputPinView()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializePin(this.Get<Border>("PinPoint"));
|
||||
InitializePin(PinPoint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ public partial class OutputPinView : PinView
|
||||
public OutputPinView()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializePin(this.Get<Border>("PinPoint"));
|
||||
InitializePin(PinPoint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,10 +3,12 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
xmlns:vm="clr-namespace:Artemis.VisualScripting.Nodes.Operators.Screens"
|
||||
x:DataType="vm:EnumEqualsNodeCustomViewModel"
|
||||
x:Class="Artemis.VisualScripting.Nodes.Operators.Screens.EnumEqualsNodeCustomView">
|
||||
<ComboBox IsEnabled="{Binding EnumValues.Count}"
|
||||
ItemsSource="{Binding EnumValues}"
|
||||
SelectedItem="{Binding CurrentValue}"
|
||||
<ComboBox IsEnabled="{CompiledBinding EnumValues.Count}"
|
||||
ItemsSource="{CompiledBinding EnumValues}"
|
||||
SelectedItem="{CompiledBinding CurrentValue}"
|
||||
PlaceholderText="Select a value"
|
||||
Classes="condensed"
|
||||
VerticalAlignment="Center">
|
||||
@ -17,7 +19,7 @@
|
||||
</ComboBox.ItemsPanel>
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding [1]}" />
|
||||
<TextBlock Text="{CompiledBinding Path=Name}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
@ -42,15 +42,15 @@ public class EnumEqualsNodeCustomViewModel : CustomNodeViewModel
|
||||
});
|
||||
}
|
||||
|
||||
public ObservableCollection<(long, string)> EnumValues { get; } = new();
|
||||
public ObservableCollection<EnumValueItem> EnumValues { get; } = new();
|
||||
|
||||
public (long, string) CurrentValue
|
||||
public EnumValueItem CurrentValue
|
||||
{
|
||||
get => EnumValues.FirstOrDefault(v => v.Item1 == _node.Storage);
|
||||
get => EnumValues.FirstOrDefault(v => v.Value == _node.Storage);
|
||||
set
|
||||
{
|
||||
if (!Equals(_node.Storage, value.Item1))
|
||||
_nodeEditorService.ExecuteCommand(Script, new UpdateStorage<long>(_node, value.Item1));
|
||||
if (!Equals(_node.Storage, value.Value))
|
||||
_nodeEditorService.ExecuteCommand(Script, new UpdateStorage<long>(_node, value.Value));
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,13 +58,38 @@ public class EnumEqualsNodeCustomViewModel : CustomNodeViewModel
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
List<(long, string)> values = Enum.GetValues(type).Cast<Enum>().Select(e => (Convert.ToInt64(e), e.Humanize())).ToList();
|
||||
List<EnumValueItem> values = Enum.GetValues(type).Cast<Enum>().Select(e => new EnumValueItem(value: Convert.ToInt64(e), name: e.Humanize())).ToList();
|
||||
if (values.Count > 20)
|
||||
EnumValues.AddRange(values.OrderBy(v => v.Item2));
|
||||
EnumValues.AddRange(values.OrderBy(v => v.Name));
|
||||
else
|
||||
EnumValues.AddRange(Enum.GetValues(type).Cast<Enum>().Select(e => (Convert.ToInt64(e), e.Humanize())));
|
||||
EnumValues.AddRange(values);
|
||||
|
||||
this.RaisePropertyChanged(nameof(CurrentValue));
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single enum value
|
||||
/// </summary>
|
||||
public class EnumValueItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="EnumValueItem" /> class.
|
||||
/// </summary>
|
||||
public EnumValueItem(long value, string name)
|
||||
{
|
||||
Value = value;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The underlying value of the enum
|
||||
/// </summary>
|
||||
public long Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the enum value
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user