Device properties - Implemented LED mappings tab

Device properties - Tweak design
This commit is contained in:
Robert committed 2022-05-15 20:14:57 +02:00
1 parent 78479c0fa2
commit a06bc68046
21 files changed
+295 -129

No files matched your search

@@ -1,16 +1,20 @@
<controls1:CoreWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
x:Class="Artemis.UI.Screens.Device.DevicePropertiesView"
Icon="/Assets/Images/Logo/application.ico"
Title="Artemis | Device Properties"
Width="1250"
Height="900">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
x:Class="Artemis.UI.Screens.Device.DevicePropertiesView"
x:DataType="device:DevicePropertiesViewModel"
Icon="/Assets/Images/Logo/application.ico"
Title="Artemis | Device Properties"
Width="1250"
Height="900">
<controls1:CoreWindow.KeyBindings>
<KeyBinding Gesture="Escape" Command="{CompiledBinding ClearSelectedLeds}" />
</controls1:CoreWindow.KeyBindings>
<Grid ColumnDefinitions="*,0,1.5*">
<Grid.Background>
<VisualBrush TileMode="Tile" Stretch="Uniform" DestinationRect="0,0,25,25">
@@ -24,45 +28,46 @@
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
<Grid Grid.Column="0" Name="DeviceDisplayGrid">
<Grid Grid.Column="0" Name="DeviceDisplayGrid" PointerReleased="DeviceDisplayGrid_OnPointerReleased">
<!-- No need to provide LEDs to highlight as LEDs are already physically highlighted -->
<shared:DeviceVisualizer Device="{Binding Device}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ShowColors="True"
Margin="20" />
<shared:DeviceVisualizer Device="{CompiledBinding Device}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ShowColors="True"
Margin="20"
LedClicked="DeviceVisualizer_OnLedClicked" />
<StackPanel Orientation="Horizontal"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"
Margin="15"
IsVisible="{Binding Device.Layout.RgbLayout.Author, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
IsVisible="{CompiledBinding Device.Layout.RgbLayout.Author, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
<TextBlock Classes="h5" Text="Device layout by " />
<TextBlock Classes="h5" FontWeight="Bold" Text="{Binding Device.Layout.RgbLayout.Author}" />
<TextBlock Classes="h5" FontWeight="Bold" Text="{CompiledBinding Device.Layout.RgbLayout.Author}" />
</StackPanel>
</Grid>
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" />
<Border Grid.Column="2" Classes="card" CornerRadius="10 0 0 0" Margin="0 10 0 0" Background="#ff323232">
<TabControl Items="{Binding Tabs}">
<Border Grid.Column="2" Classes="card-condensed" CornerRadius="10 0 0 0" Margin="0 10 0 0" Background="#ff323232">
<TabControl Items="{CompiledBinding Tabs}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
<TextBlock Text="{CompiledBinding DisplayName}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ContentControl Content="{Binding}" Margin="0 10 0 0" />
<ContentControl Content="{Binding}" Margin="0 12" />
</ScrollViewer>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Border>
<StackPanel Grid.Column="0" Grid.ColumnSpan="3" Classes="notification-container" Name="NotificationContainer" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
<StackPanel Grid.Column="0" Grid.ColumnSpan="3" Classes="notification-container" Name="NotificationContainer" VerticalAlignment="Bottom" HorizontalAlignment="Right" />
</Grid>
</controls1:CoreWindow>
@@ -1,22 +1,40 @@
using System;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Events;
using Avalonia;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Device
namespace Artemis.UI.Screens.Device;
public class DevicePropertiesView : ReactiveCoreWindow<DevicePropertiesViewModel>
{
public partial class DevicePropertiesView : ReactiveCoreWindow<DevicePropertiesViewModel>
public DevicePropertiesView()
{
public DevicePropertiesView()
{
InitializeComponent();
InitializeComponent();
#if DEBUG
this.AttachDevTools();
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void DeviceVisualizer_OnLedClicked(object? sender, LedClickedEventArgs e)
{
if (ViewModel == null)
return;
if (!e.PointerReleasedEventArgs.KeyModifiers.HasFlag(KeyModifiers.Shift))
ViewModel.SelectedLeds.Clear();
ViewModel.SelectedLeds.Add(e.Led);
}
private void DeviceDisplayGrid_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
{
if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift))
ViewModel?.ClearSelectedLeds.Execute().Subscribe();
}
}
@@ -1,15 +1,22 @@
using System.Collections.ObjectModel;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Shared;
using ReactiveUI;
using RGB.NET.Core;
using SkiaSharp;
using ArtemisLed = Artemis.Core.ArtemisLed;
namespace Artemis.UI.Screens.Device
{
public class DevicePropertiesViewModel : DialogViewModelBase<object>
{
public DevicePropertiesViewModel(ArtemisDevice device, IDeviceVmFactory deviceVmFactory)
public DevicePropertiesViewModel(ArtemisDevice device, ICoreService coreService, IDeviceVmFactory deviceVmFactory)
{
Device = device;
SelectedLeds = new ObservableCollection<ArtemisLed>();
@@ -17,13 +24,39 @@ namespace Artemis.UI.Screens.Device
Tabs.Add(deviceVmFactory.DevicePropertiesTabViewModel(device));
Tabs.Add(deviceVmFactory.DeviceInfoTabViewModel(device));
if (Device .DeviceType == RGBDeviceType.Keyboard)
if (Device.DeviceType == RGBDeviceType.Keyboard)
Tabs.Add(deviceVmFactory.InputMappingsTabViewModel(device, SelectedLeds));
Tabs.Add(deviceVmFactory.DeviceLedsTabViewModel(device, SelectedLeds));
this.WhenActivated(d =>
{
coreService.FrameRendering += CoreServiceOnFrameRendering;
Disposable.Create(() => coreService.FrameRendering -= CoreServiceOnFrameRendering).DisposeWith(d);
});
ClearSelectedLeds = ReactiveCommand.Create(ExecuteClearSelectedLeds);
}
public ArtemisDevice Device { get; }
public ObservableCollection<ArtemisLed> SelectedLeds { get; }
public ObservableCollection<ActivatableViewModelBase> Tabs { get; }
public ReactiveCommand<Unit, Unit> ClearSelectedLeds { get; }
private void ExecuteClearSelectedLeds()
{
SelectedLeds.Clear();
}
private void CoreServiceOnFrameRendering(object? sender, FrameRenderingEventArgs e)
{
if (!SelectedLeds.Any())
return;
using SKPaint highlightPaint = new() {Color = SKColors.White};
using SKPaint dimPaint = new() {Color = new SKColor(0, 0, 0, 192)};
foreach (ArtemisLed artemisLed in Device.Leds)
e.Canvas.DrawRect(artemisLed.AbsoluteRectangle, SelectedLeds.Contains(artemisLed) ? highlightPaint : dimPaint);
}
}
}
@@ -1,9 +1,10 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Device
{
public partial class DeviceInfoTabView : UserControl
public partial class DeviceInfoTabView : ReactiveUserControl<DeviceInfoTabViewModel>
{
public DeviceInfoTabView()
{
@@ -1,9 +1,10 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Device
{
public partial class DeviceLedsTabView : UserControl
public partial class DeviceLedsTabView : ReactiveUserControl<DeviceLedsTabViewModel>
{
public DeviceLedsTabView()
{
@@ -138,7 +138,12 @@
ClipValueToMinMax="True" />
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" IsChecked="{Binding DisplayOnDevices}" Content="Show preview" VerticalAlignment="Center" />
<controls:ColorPickerButton Grid.Row="3" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Color="{Binding CurrentColor, Converter={StaticResource SKColorToColorConverter}}" />
<controls:ColorPickerButton Grid.Row="3"
Grid.Column="2"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Color="{Binding CurrentColor, Converter={StaticResource SKColorToColorConverter}}"
ShowAcceptDismissButtons="False" />
</Grid>
</StackPanel>
</Grid>
@@ -168,7 +173,7 @@
UseFloatingWatermark="True"
IsReadOnly="True"
PointerReleased="InputElement_OnPointerReleased"
Padding="10 5 36 6"/>
Padding="10 5 36 6" />
<Button Classes="AppBarButton" HorizontalAlignment="Right" Command="{Binding ClearCustomLayout}" Padding="6" Margin="5 0">
<avalonia:MaterialIcon Kind="CloseCircle" />
</Button>
@@ -181,16 +186,13 @@
<!-- Buttons -->
<Grid Grid.Row="1" ColumnDefinitions="Auto,*">
<Button Grid.Column="0"
Classes="AppBarButton"
Command="{Binding SelectPhysicalLayout}"
ToolTip.Tip="Restart device setup, allowing you to select a new physical and logical layout">
<Button Grid.Column="0" Command="{Binding SelectPhysicalLayout}" ToolTip.Tip="Restart device setup, allowing you to select a new physical and logical layout">
Restart setup
</Button>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Classes="AppBarButton" IsCancel="True" Command="{Binding Reset}" Margin="0 0 5 0">Reset</Button>
<Button IsDefault="True" Command="{Binding Apply}">Apply</Button>
<Button IsCancel="True" Command="{Binding Reset}" Margin="0 0 5 0">Reset</Button>
<Button Classes="accent" IsDefault="True" Command="{Binding Apply}">Apply</Button>
</StackPanel>
</Grid>
</Grid>
@@ -240,9 +240,9 @@ namespace Artemis.UI.Screens.Device
HasRoomCategory = Device.Categories.Contains(DeviceCategory.Room);
HasPeripheralsCategory = Device.Categories.Contains(DeviceCategory.Peripherals);
Device.RedScale = _initialRedScale;
Device.GreenScale = _initialGreenScale;
Device.BlueScale = _initialBlueScale;
RedScale = _initialRedScale * 100;
GreenScale = _initialGreenScale * 100;
BlueScale = _initialBlueScale * 100;
}
private bool GetCategory(DeviceCategory category)
@@ -254,7 +254,7 @@ namespace Artemis.UI.Screens.Device
{
if (value && !_categories.Contains(category))
_categories.Add(category);
else
else if (!value)
_categories.Remove(category);
this.RaisePropertyChanged($"Has{category}Category");
@@ -2,7 +2,73 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Device.InputMappingsTabView">
Welcome to Avalonia!
</UserControl>
x:Class="Artemis.UI.Screens.Device.InputMappingsTabView"
x:DataType="device:InputMappingsTabViewModel">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBlock Classes="h4">
Introduction
</TextBlock>
<TextBlock TextWrapping="Wrap">
In some cases you may want Artemis to map key presses to different LEDs.
</TextBlock>
<TextBlock TextWrapping="Wrap" Margin="0 13 0 0">
This is useful when your logical layout swaps keys around (like Hungarian layouts where the Z and Y keys are swapped). In this tab you can set up these custom input mappings, simply click on a LED and press a key, Artemis will from then on consider that LED pressed whenever you press the same key again.
</TextBlock>
</StackPanel>
<TextBlock Grid.Row="1"
Margin="0 20"
Classes="h4"
TextAlignment="Center"
IsVisible="{CompiledBinding SelectedLed, Converter={x:Static ObjectConverters.IsNull}}">
Select a LED in the preview on the left side to get started...
</TextBlock>
<StackPanel Grid.Row="1" Margin="0 20" IsVisible="{CompiledBinding SelectedLed, Converter={x:Static ObjectConverters.IsNotNull}}">
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="6">
<TextBlock Classes="h4" TextAlignment="Center">Current target LED: </TextBlock>
<TextBlock Classes="h4" TextAlignment="Center" Text="{CompiledBinding SelectedLed.RgbLed.Id, Mode=OneWay, FallbackValue='none'}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="5">
<TextBlock TextAlignment="Center">Press the key you want to remap</TextBlock>
<TextBlock TextAlignment="Center" FontWeight="Bold" Text="{CompiledBinding SelectedLed.RgbLed.Id, Mode=OneWay, FallbackValue='none'}"/>
<TextBlock TextAlignment="Center">to ...</TextBlock>
</StackPanel>
</StackPanel>
<DataGrid Grid.Row="2"
Items="{CompiledBinding InputMappings}"
CanUserSortColumns="True"
IsReadOnly="True"
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="*" />
<DataGridTemplateColumn Width="Auto" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding $parent[UserControl].DataContext.DeleteMapping}"
CommandParameter="{Binding}"
Classes="icon-button"
ToolTip.Tip="Delete mapping"
HorizontalAlignment="Center">
<avalonia:MaterialIcon Kind="Delete" />
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
@@ -1,9 +1,10 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Device
{
public partial class InputMappingsTabView : UserControl
public partial class InputMappingsTabView : ReactiveUserControl<InputMappingsTabViewModel>
{
public InputMappingsTabView()
{
@@ -2,6 +2,7 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive.Disposables;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Exceptions;
@@ -30,8 +31,23 @@ namespace Artemis.UI.Screens.Device
Device = device;
DisplayName = "Input Mappings";
InputMappings = new ObservableCollection<(ArtemisLed, ArtemisLed)>();
this.WhenActivated(d =>
{
_selectedLeds.CollectionChanged += SelectedLedsOnCollectionChanged;
_inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
UpdateInputMappings();
Disposable.Create(() =>
{
_selectedLeds.CollectionChanged -= SelectedLedsOnCollectionChanged;
_inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
InputMappings.Clear();
}).DisposeWith(d);
});
}
public ArtemisDevice Device { get; }
public ArtemisLed? SelectedLed
@@ -42,13 +58,13 @@ namespace Artemis.UI.Screens.Device
public ObservableCollection<(ArtemisLed, ArtemisLed)> InputMappings { get; }
public void DeleteMapping(Tuple<ArtemisLed, ArtemisLed> inputMapping)
public void DeleteMapping((ArtemisLed, ArtemisLed) inputMapping)
{
Device.InputMappings.Remove(inputMapping.Item1);
UpdateInputMappings();
}
private void InputServiceOnKeyboardKeyUp(object sender, ArtemisKeyboardKeyEventArgs e)
private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e)
{
if (SelectedLed == null || e.Led == null)
return;
@@ -64,7 +80,7 @@ namespace Artemis.UI.Screens.Device
// Apply the new LED mapping
Device.InputMappings[SelectedLed] = artemisLed;
_rgbService.SaveDevice(Device);
// ((DeviceDialogViewModel) Parent).SelectedLeds.Clear();
_selectedLeds.Clear();
UpdateInputMappings();
}
@@ -74,35 +90,13 @@ namespace Artemis.UI.Screens.Device
if (InputMappings.Any())
InputMappings.Clear();
// InputMappings.AddRange(Device.InputMappings.Select(m => new Tuple<ArtemisLed, ArtemisLed>(m.Key, m.Value)));
foreach ((ArtemisLed, ArtemisLed) tuple in Device.InputMappings.Select(m => (m.Key, m.Value)))
InputMappings.Add(tuple);
}
private void SelectedLedsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
private void SelectedLedsOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
// SelectedLed = ((DeviceDialogViewModel) Parent).SelectedLeds.FirstOrDefault();
SelectedLed = _selectedLeds.FirstOrDefault();
}
//
// #region Overrides of Screen
//
// /// <inheritdoc />
// protected override void OnActivate()
// {
// UpdateInputMappings();
// _inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
// ((DeviceDialogViewModel) Parent).SelectedLeds.CollectionChanged += SelectedLedsOnCollectionChanged;
//
// base.OnActivate();
// }
//
// /// <inheritdoc />
// protected override void OnDeactivate()
// {
// InputMappings.Clear();
// _inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
// ((DeviceDialogViewModel) Parent).SelectedLeds.CollectionChanged -= SelectedLedsOnCollectionChanged;
// base.OnDeactivate();
// }
//
// #endregion
}
}