From 46d3a288e9a4bee1cb618e080b68a32685c4609a Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 9 Mar 2021 00:30:11 +0100 Subject: [PATCH] UI - Added keyboard layout selection UI --- .../Models/Surface/ArtemisDevice.cs | 5 +- src/Artemis.Core/Services/DeviceService.cs | 3 +- .../Controls/DeviceVisualizerLed.cs | 6 +- .../Screens/Dialogs/ConfirmDialogView.xaml | 2 +- src/Artemis.UI/Artemis.UI.csproj | 10 + .../Resources/Images/PhysicalLayouts/abnt.png | Bin 0 -> 27843 bytes .../Resources/Images/PhysicalLayouts/ansi.png | Bin 0 -> 27167 bytes .../Resources/Images/PhysicalLayouts/iso.png | Bin 0 -> 27664 bytes .../Resources/Images/PhysicalLayouts/jis.png | Bin 0 -> 28370 bytes .../Resources/Images/PhysicalLayouts/ks.png | Bin 0 -> 27508 bytes .../Settings/Debug/Tabs/RenderDebugView.xaml | 8 +- .../Debug/Tabs/RenderDebugViewModel.cs | 16 ++ .../Device/DeviceLayoutDialogView.xaml | 187 ++++++++++++++++++ .../Device/DeviceLayoutDialogViewModel.cs | 125 ++++++++++++ .../Device/Tabs/DeviceInfoTabViewModel.cs | 2 +- .../Device/Tabs/DevicePropertiesTabView.xaml | 4 + .../Tabs/DevicePropertiesTabViewModel.cs | 20 +- .../Tabs/Devices/DeviceSettingsViewModel.cs | 2 +- .../SurfaceEditor/SurfaceEditorViewModel.cs | 2 +- .../Services/DeviceLayoutService.cs | 80 ++++++++ 20 files changed, 460 insertions(+), 12 deletions(-) create mode 100644 src/Artemis.UI/Resources/Images/PhysicalLayouts/abnt.png create mode 100644 src/Artemis.UI/Resources/Images/PhysicalLayouts/ansi.png create mode 100644 src/Artemis.UI/Resources/Images/PhysicalLayouts/iso.png create mode 100644 src/Artemis.UI/Resources/Images/PhysicalLayouts/jis.png create mode 100644 src/Artemis.UI/Resources/Images/PhysicalLayouts/ks.png create mode 100644 src/Artemis.UI/Screens/Settings/Device/DeviceLayoutDialogView.xaml create mode 100644 src/Artemis.UI/Screens/Settings/Device/DeviceLayoutDialogViewModel.cs create mode 100644 src/Artemis.UI/Services/DeviceLayoutService.cs diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs index 661130160..81494101f 100644 --- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs +++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs @@ -306,7 +306,7 @@ namespace Artemis.Core { // Take out invalid file name chars, may not be perfect but neither are you string fileName = System.IO.Path.GetInvalidFileNameChars().Aggregate(RgbDevice.DeviceInfo.Model, (current, c) => current.Replace(c, '-')); - if (RgbDevice is IKeyboard) + if (RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard) fileName = $"{fileName}-{PhysicalLayout.ToString().ToUpper()}"; if (includeExtension) fileName = $"{fileName}.xml"; @@ -388,9 +388,10 @@ namespace Artemis.Core private void ApplyKeyboardLayout() { - if (!(RgbDevice is IKeyboard keyboard)) + if (RgbDevice.DeviceInfo.DeviceType != RGBDeviceType.Keyboard) return; + IKeyboard keyboard = (IKeyboard) RgbDevice; // If supported, detect the device layout so that we can load the correct one if (DeviceProvider.CanDetectLogicalLayout) LogicalLayout = DeviceProvider.GetLogicalLayout(keyboard); diff --git a/src/Artemis.Core/Services/DeviceService.cs b/src/Artemis.Core/Services/DeviceService.cs index 68329ac77..e39616844 100644 --- a/src/Artemis.Core/Services/DeviceService.cs +++ b/src/Artemis.Core/Services/DeviceService.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using RGB.NET.Core; diff --git a/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs b/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs index 28fde6cca..35adaf092 100644 --- a/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs +++ b/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs @@ -12,9 +12,12 @@ namespace Artemis.UI.Shared { internal class DeviceVisualizerLed { + private const byte Dimmed = 100; + private const byte NonDimmed = 255; + private SolidColorBrush? _renderColorBrush; private Color _renderColor; - + public DeviceVisualizerLed(ArtemisLed led) { Led = led; @@ -49,6 +52,7 @@ namespace Artemis.UI.Shared byte b = Led.RgbLed.Color.GetB(); _renderColor.A = (byte)(isDimmed ? 100 : 255); + _renderColor.A = isDimmed ? Dimmed : NonDimmed; _renderColor.R = r; _renderColor.G = g; _renderColor.B = b; diff --git a/src/Artemis.UI.Shared/Screens/Dialogs/ConfirmDialogView.xaml b/src/Artemis.UI.Shared/Screens/Dialogs/ConfirmDialogView.xaml index 9fced07e6..9438e4b64 100644 --- a/src/Artemis.UI.Shared/Screens/Dialogs/ConfirmDialogView.xaml +++ b/src/Artemis.UI.Shared/Screens/Dialogs/ConfirmDialogView.xaml @@ -17,7 +17,7 @@ Text="{Binding Text}" TextWrapping="Wrap" /> - + + + + + + + + + + + + + + + + + + Select a logical layout + + + Artemis couldn't automatically determine the logical layout of your . + While not as important as the physical layout, setting the correct logical layout will allow Artemis to show the right keycaps (if a matching layout file is present) + + + + + + + + + () + + + + + + + + diff --git a/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs index 4de139698..19f425e70 100644 --- a/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.Generic; +using System.ComponentModel; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Input; @@ -15,6 +16,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs { private readonly ICoreService _coreService; private readonly IMessageService _messageService; + private readonly IDialogService _dialogService; private readonly IRgbService _rgbService; private float _blueScale; private SKColor _currentColor; @@ -33,11 +35,13 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs ICoreService coreService, IRgbService rgbService, IMessageService messageService, + IDialogService dialogService, IModelValidator validator) : base(validator) { _coreService = coreService; _rgbService = rgbService; _messageService = messageService; + _dialogService = dialogService; Device = device; DisplayName = "PROPERTIES"; @@ -126,6 +130,11 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs } } + public async Task SelectPhysicalLayout() + { + await _dialogService.ShowDialog(new Dictionary {{"device", Device}}); + } + public async Task Apply() { await ValidateAsync(); @@ -167,12 +176,21 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs _initialGreenScale = Device.GreenScale; _initialBlueScale = Device.BlueScale; CurrentColor = SKColors.White; + _coreService.FrameRendering += OnFrameRendering; Device.PropertyChanged += DeviceOnPropertyChanged; base.OnActivate(); } + protected override void OnDeactivate() + { + _coreService.FrameRendering -= OnFrameRendering; + Device.PropertyChanged -= DeviceOnPropertyChanged; + + base.OnDeactivate(); + } + #region Event handlers private void DeviceOnPropertyChanged(object sender, PropertyChangedEventArgs e) diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs index c8cb5d0cd..2005b6753 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs @@ -84,7 +84,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices public void ViewProperties() { - _windowManager.ShowDialog(_deviceDebugVmFactory.DeviceDialogViewModel(Device)); + _windowManager.ShowWindow(_deviceDebugVmFactory.DeviceDialogViewModel(Device)); } private async Task UpdateIsDeviceEnabled(bool value) { diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs index 1700dc144..917024ec6 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs @@ -241,7 +241,7 @@ namespace Artemis.UI.Screens.SurfaceEditor public void ViewProperties(ArtemisDevice device) { - _windowManager.ShowDialog(_deviceDebugVmFactory.DeviceDialogViewModel(device)); + _windowManager.ShowWindow(_deviceDebugVmFactory.DeviceDialogViewModel(device)); } public async Task DetectInput(ArtemisDevice device) diff --git a/src/Artemis.UI/Services/DeviceLayoutService.cs b/src/Artemis.UI/Services/DeviceLayoutService.cs new file mode 100644 index 000000000..d30e9bdae --- /dev/null +++ b/src/Artemis.UI/Services/DeviceLayoutService.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Artemis.Core; +using Artemis.Core.Services; +using Artemis.UI.Screens.Settings.Device; +using Artemis.UI.Shared.Services; +using MaterialDesignThemes.Wpf; +using RGB.NET.Core; +using RGB.NET.Layout; +using KeyboardLayoutType = Artemis.Core.KeyboardLayoutType; + +namespace Artemis.UI.Services +{ + public class DeviceLayoutService : IDeviceLayoutService + { + private readonly IDialogService _dialogService; + private readonly IRgbService _rgbService; + private readonly IWindowService _windowService; + private readonly IMessageService _messageService; + private readonly List _ignoredDevices; + + public DeviceLayoutService(IDialogService dialogService, IRgbService rgbService, IWindowService windowService, IMessageService messageService) + { + _dialogService = dialogService; + _rgbService = rgbService; + _windowService = windowService; + _messageService = messageService; + _ignoredDevices = new List(); + + rgbService.DeviceAdded += RgbServiceOnDeviceAdded; + windowService.MainWindowOpened += async (_, _) => await RequestLayoutInput(); + } + + private async Task RequestLayoutInput() + { + List devices = _rgbService.Devices.Where(device => DeviceNeedsLayout(device) && !_ignoredDevices.Contains(device)).ToList(); + foreach (ArtemisDevice artemisDevice in devices) + { + bool configure = await _dialogService.ShowConfirmDialog( + "Device requires layout info", + $"Artemis could not detect the layout of your {artemisDevice.RgbDevice.DeviceInfo.DeviceName}. Please configure out manually", + "Configure", + "Ignore for now" + ); + + if (!configure) + { + _ignoredDevices.Add(artemisDevice); + continue; + } + + await _dialogService.ShowDialog(new Dictionary {{"device", artemisDevice}}); + } + } + + private void RgbServiceOnDeviceAdded(object sender, DeviceEventArgs e) + { + if (!DeviceNeedsLayout(e.Device)) + return; + + if (!_windowService.IsMainWindowOpen) + { + _messageService.ShowNotification("New device detected", "Detected a new device that needs layout setup", PackIconKind.Keyboard); + return; + } + } + + private bool DeviceNeedsLayout(ArtemisDevice d) => d.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard && + d.LogicalLayout == null || + d.PhysicalLayout == KeyboardLayoutType.Unknown && + (!d.DeviceProvider.CanDetectLogicalLayout || !d.DeviceProvider.CanDetectPhysicalLayout); + } + + public interface IDeviceLayoutService : IArtemisUIService + { + } +} \ No newline at end of file