mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
UI - Added keyboard layout selection UI
This commit is contained in:
parent
ea1633c322
commit
46d3a288e9
@ -306,7 +306,7 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
// Take out invalid file name chars, may not be perfect but neither are you
|
// 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, '-'));
|
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()}";
|
fileName = $"{fileName}-{PhysicalLayout.ToString().ToUpper()}";
|
||||||
if (includeExtension)
|
if (includeExtension)
|
||||||
fileName = $"{fileName}.xml";
|
fileName = $"{fileName}.xml";
|
||||||
@ -388,9 +388,10 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
private void ApplyKeyboardLayout()
|
private void ApplyKeyboardLayout()
|
||||||
{
|
{
|
||||||
if (!(RgbDevice is IKeyboard keyboard))
|
if (RgbDevice.DeviceInfo.DeviceType != RGBDeviceType.Keyboard)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
IKeyboard keyboard = (IKeyboard) RgbDevice;
|
||||||
// If supported, detect the device layout so that we can load the correct one
|
// If supported, detect the device layout so that we can load the correct one
|
||||||
if (DeviceProvider.CanDetectLogicalLayout)
|
if (DeviceProvider.CanDetectLogicalLayout)
|
||||||
LogicalLayout = DeviceProvider.GetLogicalLayout(keyboard);
|
LogicalLayout = DeviceProvider.GetLogicalLayout(keyboard);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
|
|
||||||
|
|||||||
@ -12,9 +12,12 @@ namespace Artemis.UI.Shared
|
|||||||
{
|
{
|
||||||
internal class DeviceVisualizerLed
|
internal class DeviceVisualizerLed
|
||||||
{
|
{
|
||||||
|
private const byte Dimmed = 100;
|
||||||
|
private const byte NonDimmed = 255;
|
||||||
|
|
||||||
private SolidColorBrush? _renderColorBrush;
|
private SolidColorBrush? _renderColorBrush;
|
||||||
private Color _renderColor;
|
private Color _renderColor;
|
||||||
|
|
||||||
public DeviceVisualizerLed(ArtemisLed led)
|
public DeviceVisualizerLed(ArtemisLed led)
|
||||||
{
|
{
|
||||||
Led = led;
|
Led = led;
|
||||||
@ -49,6 +52,7 @@ namespace Artemis.UI.Shared
|
|||||||
byte b = Led.RgbLed.Color.GetB();
|
byte b = Led.RgbLed.Color.GetB();
|
||||||
|
|
||||||
_renderColor.A = (byte)(isDimmed ? 100 : 255);
|
_renderColor.A = (byte)(isDimmed ? 100 : 255);
|
||||||
|
_renderColor.A = isDimmed ? Dimmed : NonDimmed;
|
||||||
_renderColor.R = r;
|
_renderColor.R = r;
|
||||||
_renderColor.G = g;
|
_renderColor.G = g;
|
||||||
_renderColor.B = b;
|
_renderColor.B = b;
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
Text="{Binding Text}"
|
Text="{Binding Text}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 8 0 0">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="16">
|
||||||
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
Focusable="False"
|
Focusable="False"
|
||||||
IsCancel="True"
|
IsCancel="True"
|
||||||
|
|||||||
@ -126,6 +126,11 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="Resources\Cursors\aero_rotate.cur" />
|
<Resource Include="Resources\Cursors\aero_rotate.cur" />
|
||||||
|
<Resource Include="Resources\Images\PhysicalLayouts\abnt.png" />
|
||||||
|
<Resource Include="Resources\Images\PhysicalLayouts\ansi.png" />
|
||||||
|
<Resource Include="Resources\Images\PhysicalLayouts\iso.png" />
|
||||||
|
<Resource Include="Resources\Images\PhysicalLayouts\jis.png" />
|
||||||
|
<Resource Include="Resources\Images\PhysicalLayouts\ks.png" />
|
||||||
<Resource Include="Resources\Images\Sidebar\sidebar-header.png" />
|
<Resource Include="Resources\Images\Sidebar\sidebar-header.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -306,6 +311,11 @@
|
|||||||
<None Remove="Resources\Fonts\RobotoMono-Regular.ttf" />
|
<None Remove="Resources\Fonts\RobotoMono-Regular.ttf" />
|
||||||
<None Remove="Resources\Images\Logo\bow.svg" />
|
<None Remove="Resources\Images\Logo\bow.svg" />
|
||||||
<None Remove="Resources\Images\Logo\logo-512.ico" />
|
<None Remove="Resources\Images\Logo\logo-512.ico" />
|
||||||
|
<None Remove="Resources\Images\PhysicalLayouts\abnt.png" />
|
||||||
|
<None Remove="Resources\Images\PhysicalLayouts\ansi.png" />
|
||||||
|
<None Remove="Resources\Images\PhysicalLayouts\iso.png" />
|
||||||
|
<None Remove="Resources\Images\PhysicalLayouts\jis.png" />
|
||||||
|
<None Remove="Resources\Images\PhysicalLayouts\ks.png" />
|
||||||
<None Remove="Resources\Images\Sidebar\sidebar-header.png" />
|
<None Remove="Resources\Images\Sidebar\sidebar-header.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/abnt.png
Normal file
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/abnt.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/ansi.png
Normal file
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/ansi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/iso.png
Normal file
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/iso.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/jis.png
Normal file
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/jis.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/ks.png
Normal file
BIN
src/Artemis.UI/Resources/Images/PhysicalLayouts/ks.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
@ -27,10 +27,12 @@
|
|||||||
<TextBlock Grid.Column="0">
|
<TextBlock Grid.Column="0">
|
||||||
This image shows what is being rendered and dispatched to RGB.NET
|
This image shows what is being rendered and dispatched to RGB.NET
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock Grid.Column="1" HorizontalAlignment="Right" Margin="0,0,5,0" FontWeight="Bold">
|
<TextBlock Grid.Column="1" HorizontalAlignment="Right" Margin="0,0,5,0">
|
||||||
FPS:
|
<Run Text="FPS: "></Run>
|
||||||
|
<Run FontWeight="Bold" Text="{Binding CurrentFps}"></Run>
|
||||||
|
<Run Text=" at "></Run>
|
||||||
|
<Run Text="{Binding RenderWidth}"/><Run Text="x"></Run><Run Text="{Binding RenderHeight}"/>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock Grid.Column="2" HorizontalAlignment="Right" Text="{Binding CurrentFps}" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<materialDesign:Card Grid.Row="2" Margin="0,5,0,0" Background="{StaticResource Checkerboard}">
|
<materialDesign:Card Grid.Row="2" Margin="0,5,0,0" Background="{StaticResource Checkerboard}">
|
||||||
|
|||||||
@ -15,6 +15,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
|||||||
private readonly ICoreService _coreService;
|
private readonly ICoreService _coreService;
|
||||||
private double _currentFps;
|
private double _currentFps;
|
||||||
private ImageSource _currentFrame;
|
private ImageSource _currentFrame;
|
||||||
|
private int _renderWidth;
|
||||||
|
private int _renderHeight;
|
||||||
|
|
||||||
public RenderDebugViewModel(ICoreService coreService)
|
public RenderDebugViewModel(ICoreService coreService)
|
||||||
{
|
{
|
||||||
@ -34,6 +36,18 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
|||||||
set => SetAndNotify(ref _currentFps, value);
|
set => SetAndNotify(ref _currentFps, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int RenderWidth
|
||||||
|
{
|
||||||
|
get => _renderWidth;
|
||||||
|
set => SetAndNotify(ref _renderWidth, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int RenderHeight
|
||||||
|
{
|
||||||
|
get => _renderHeight;
|
||||||
|
set => SetAndNotify(ref _renderHeight, value);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnActivate()
|
protected override void OnActivate()
|
||||||
{
|
{
|
||||||
_coreService.FrameRendered += CoreServiceOnFrameRendered;
|
_coreService.FrameRendered += CoreServiceOnFrameRendered;
|
||||||
@ -56,6 +70,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
SKImageInfo bitmapInfo = e.Texture.Bitmap.Info;
|
SKImageInfo bitmapInfo = e.Texture.Bitmap.Info;
|
||||||
|
RenderHeight = bitmapInfo.Height;
|
||||||
|
RenderWidth = bitmapInfo.Width;
|
||||||
|
|
||||||
if (!(CurrentFrame is WriteableBitmap writeableBitmap) ||
|
if (!(CurrentFrame is WriteableBitmap writeableBitmap) ||
|
||||||
writeableBitmap.Width != bitmapInfo.Width ||
|
writeableBitmap.Width != bitmapInfo.Width ||
|
||||||
|
|||||||
@ -0,0 +1,187 @@
|
|||||||
|
<UserControl x:Class="Artemis.UI.Screens.Settings.Device.DeviceLayoutDialogView"
|
||||||
|
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:Artemis.UI.Screens.Settings.Device"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:mde="https://spiegelp.github.io/MaterialDesignExtensions/winfx/xaml"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="1200" d:DesignWidth="1200"
|
||||||
|
d:DataContext="{d:DesignInstance local:DeviceLayoutDialogViewModel}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid Grid.Row="0" Margin="16" Width="1200" Height="800" Visibility="{Binding SelectPhysicalLayout, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Grid.Row="0">
|
||||||
|
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" Margin="0 0 0 20">
|
||||||
|
Select a physical layout
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||||
|
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||||
|
TextWrapping="Wrap">
|
||||||
|
Artemis couldn't automatically determine the physical layout of your <Run Text="{Binding Device.RgbDevice.DeviceInfo.DeviceName, Mode=OneWay}" />. <LineBreak />
|
||||||
|
In order for Artemis to know which keys are on your keyboard and where they're located, select the matching layout below.
|
||||||
|
<LineBreak />
|
||||||
|
<LineBreak />
|
||||||
|
P.S. Don't worry about missing special keys like num keys/function keys or macro keys, they aren't important here.
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<ScrollViewer Grid.Row="1" Margin="0 25">
|
||||||
|
<WrapPanel HorizontalAlignment="Center">
|
||||||
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
Foreground="{DynamicResource MaterialDesignBody}"
|
||||||
|
Command="{s:Action ApplyPhysicalLayout}"
|
||||||
|
CommandParameter="ISO"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="0 0 10 0"
|
||||||
|
Width="550"
|
||||||
|
Height="280">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="/Resources/Images/PhysicalLayouts/iso.png" />
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0 10 0 0">
|
||||||
|
ISO
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignBody2TextBlock}" TextWrapping="Wrap">
|
||||||
|
Most commonly used in the EU (tall enter)
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
Foreground="{DynamicResource MaterialDesignBody}"
|
||||||
|
Command="{s:Action ApplyPhysicalLayout}"
|
||||||
|
CommandParameter="ANSI"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="0 0 10 0"
|
||||||
|
Width="550"
|
||||||
|
Height="280">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="/Resources/Images/PhysicalLayouts/ansi.png" />
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0 10 0 0">
|
||||||
|
ANSI
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignBody2TextBlock}" TextWrapping="Wrap">
|
||||||
|
Most commonly used in the US (short enter)
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
Foreground="{DynamicResource MaterialDesignBody}"
|
||||||
|
Command="{s:Action ApplyPhysicalLayout}"
|
||||||
|
CommandParameter="ABNT"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="0 0 10 0"
|
||||||
|
Width="550"
|
||||||
|
Height="280">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="/Resources/Images/PhysicalLayouts/abnt.png" />
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0 10 0 0">
|
||||||
|
ABNT
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignBody2TextBlock}" TextWrapping="Wrap">
|
||||||
|
Most commonly used in Brazil/Portugal (based on ISO)
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
Foreground="{DynamicResource MaterialDesignBody}"
|
||||||
|
Command="{s:Action ApplyPhysicalLayout}"
|
||||||
|
CommandParameter="KS"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="0 0 10 0"
|
||||||
|
Width="550"
|
||||||
|
Height="280">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="/Resources/Images/PhysicalLayouts/ks.png" />
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0 10 0 0">
|
||||||
|
KS
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignBody2TextBlock}" TextWrapping="Wrap">
|
||||||
|
Most commonly used in South Korea
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
Foreground="{DynamicResource MaterialDesignBody}"
|
||||||
|
Command="{s:Action ApplyPhysicalLayout}"
|
||||||
|
CommandParameter="JIS"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Margin="0 0 10 0"
|
||||||
|
Width="550"
|
||||||
|
Height="280">
|
||||||
|
<StackPanel>
|
||||||
|
<Image Source="/Resources/Images/PhysicalLayouts/jis.png" />
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0 10 0 0">
|
||||||
|
JIS
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextAlignment="Center" Style="{StaticResource MaterialDesignBody2TextBlock}" TextWrapping="Wrap">
|
||||||
|
Most commonly used in Japan (based on ISO)
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</WrapPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="0" Margin="16" Width="800" Visibility="{Binding SelectPhysicalLayout, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" Margin="0 0 0 20">
|
||||||
|
Select a logical layout
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||||
|
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||||
|
TextWrapping="Wrap">
|
||||||
|
Artemis couldn't automatically determine the logical layout of your <Run Text="{Binding Device.RgbDevice.DeviceInfo.DeviceName, Mode=OneWay}" />. <LineBreak /><LineBreak />
|
||||||
|
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)
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<mde:Autocomplete Style="{StaticResource MaterialDesignAutocomplete}"
|
||||||
|
AutocompleteSource="{Binding Path=AutocompleteSource}"
|
||||||
|
SearchOnInitialFocus="True"
|
||||||
|
SelectedItem="{Binding SelectedRegion, Mode=TwoWay}"
|
||||||
|
Hint="Select a logical layout"
|
||||||
|
Margin="0,16,0,0"
|
||||||
|
FontSize="15"
|
||||||
|
Foreground="{DynamicResource MaterialDesignBody}"
|
||||||
|
Background="{DynamicResource MaterialDesignPaper}">
|
||||||
|
<mde:Autocomplete.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock FontSize="14" VerticalAlignment="Center">
|
||||||
|
<Run Text="{Binding EnglishName, Mode=OneWay}" />
|
||||||
|
(<Run FontWeight="SemiBold" Text="{Binding TwoLetterISORegionName, Mode=OneWay}" />)
|
||||||
|
</TextBlock>
|
||||||
|
</DataTemplate>
|
||||||
|
</mde:Autocomplete.ItemTemplate>
|
||||||
|
</mde:Autocomplete>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="16">
|
||||||
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
Focusable="False"
|
||||||
|
IsCancel="True"
|
||||||
|
Command="{s:Action Cancel}"
|
||||||
|
Content="CANCEL" />
|
||||||
|
<Button x:Name="ConfirmButton"
|
||||||
|
Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
|
IsDefault="True"
|
||||||
|
Focusable="True"
|
||||||
|
Command="{s:Action Confirm}"
|
||||||
|
Content="CONFIRM" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using MaterialDesignExtensions.Model;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Settings.Device
|
||||||
|
{
|
||||||
|
public class DeviceLayoutDialogViewModel : DialogViewModelBase
|
||||||
|
{
|
||||||
|
private readonly IRgbService _rgbService;
|
||||||
|
private bool _selectPhysicalLayout;
|
||||||
|
private RegionInfoAutocompleteSource _autocompleteSource;
|
||||||
|
private RegionInfo _selectedRegion;
|
||||||
|
|
||||||
|
public DeviceLayoutDialogViewModel(ArtemisDevice device, IRgbService rgbService)
|
||||||
|
{
|
||||||
|
_rgbService = rgbService;
|
||||||
|
Device = device;
|
||||||
|
SelectPhysicalLayout = !device.DeviceProvider.CanDetectPhysicalLayout;
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
AutocompleteSource = new RegionInfoAutocompleteSource();
|
||||||
|
SelectedRegion = AutocompleteSource.Regions.FirstOrDefault(r => r.TwoLetterISORegionName == Device.LogicalLayout ||
|
||||||
|
r.TwoLetterISORegionName == "US" && Device.LogicalLayout == "NA");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArtemisDevice Device { get; }
|
||||||
|
|
||||||
|
public RegionInfoAutocompleteSource AutocompleteSource
|
||||||
|
{
|
||||||
|
get => _autocompleteSource;
|
||||||
|
set => SetAndNotify(ref _autocompleteSource, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionInfo SelectedRegion
|
||||||
|
{
|
||||||
|
get => _selectedRegion;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetAndNotify(ref _selectedRegion, value);
|
||||||
|
NotifyOfPropertyChange(nameof(CanConfirm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SelectPhysicalLayout
|
||||||
|
{
|
||||||
|
get => _selectPhysicalLayout;
|
||||||
|
set => SetAndNotify(ref _selectPhysicalLayout, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanConfirm => SelectedRegion != null;
|
||||||
|
|
||||||
|
public void ApplyPhysicalLayout(string physicalLayout)
|
||||||
|
{
|
||||||
|
Device.PhysicalLayout = Enum.Parse<KeyboardLayoutType>(physicalLayout);
|
||||||
|
|
||||||
|
_rgbService.SaveDevice(Device);
|
||||||
|
_rgbService.ApplyBestDeviceLayout(Device);
|
||||||
|
|
||||||
|
SelectPhysicalLayout = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyLogicalLayout(string logicalLayout)
|
||||||
|
{
|
||||||
|
Device.LogicalLayout = logicalLayout;
|
||||||
|
|
||||||
|
_rgbService.SaveDevice(Device);
|
||||||
|
_rgbService.ApplyBestDeviceLayout(Device);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Confirm()
|
||||||
|
{
|
||||||
|
if (!CanConfirm || Session == null || Session.IsEnded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyLogicalLayout(SelectedRegion.TwoLetterISORegionName);
|
||||||
|
Session?.Close(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RegionInfoAutocompleteSource : IAutocompleteSource<RegionInfo>
|
||||||
|
{
|
||||||
|
public List<RegionInfo> Regions { get; set; }
|
||||||
|
|
||||||
|
public RegionInfoAutocompleteSource()
|
||||||
|
{
|
||||||
|
Regions = CultureInfo.GetCultures(CultureTypes.SpecificCultures).ToList()
|
||||||
|
.Select(c => new RegionInfo(c.LCID))
|
||||||
|
.GroupBy(r => r.EnglishName)
|
||||||
|
.Select(g => g.First())
|
||||||
|
.OrderBy(r => r.EnglishName)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<RegionInfo> IAutocompleteSource<RegionInfo>.Search(string searchTerm)
|
||||||
|
{
|
||||||
|
if (searchTerm == null)
|
||||||
|
return Regions;
|
||||||
|
|
||||||
|
searchTerm = searchTerm.ToLower();
|
||||||
|
return Regions.Where(r => r.EnglishName.ToLower().Contains(searchTerm) ||
|
||||||
|
r.NativeName.ToLower().Contains(searchTerm) ||
|
||||||
|
r.TwoLetterISORegionName.ToLower().Contains(searchTerm));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable Search(string searchTerm)
|
||||||
|
{
|
||||||
|
if (searchTerm == null)
|
||||||
|
return Regions;
|
||||||
|
|
||||||
|
searchTerm = searchTerm.ToLower();
|
||||||
|
return Regions.Where(r => r.EnglishName.ToLower().Contains(searchTerm) ||
|
||||||
|
r.NativeName.ToLower().Contains(searchTerm) ||
|
||||||
|
r.TwoLetterISORegionName.ToLower().Contains(searchTerm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,7 +12,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
|||||||
DisplayName = "INFO";
|
DisplayName = "INFO";
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsKeyboard => Device.RgbDevice is IKeyboard;
|
public bool IsKeyboard => Device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard;
|
||||||
public ArtemisDevice Device { get; }
|
public ArtemisDevice Device { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,6 +174,10 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</materialDesign:HintAssist.Hint>
|
</materialDesign:HintAssist.Hint>
|
||||||
</TextBox>
|
</TextBox>
|
||||||
|
|
||||||
|
<Button Style="{StaticResource MaterialDesignRaisedButton}" Margin="0 8 8 0" Command="{s:Action SelectPhysicalLayout}">
|
||||||
|
SELECT PHYSICAL LAYOUT (PLACEHOLDER)
|
||||||
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Buttons -->
|
<!-- Buttons -->
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
@ -15,6 +16,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
|||||||
{
|
{
|
||||||
private readonly ICoreService _coreService;
|
private readonly ICoreService _coreService;
|
||||||
private readonly IMessageService _messageService;
|
private readonly IMessageService _messageService;
|
||||||
|
private readonly IDialogService _dialogService;
|
||||||
private readonly IRgbService _rgbService;
|
private readonly IRgbService _rgbService;
|
||||||
private float _blueScale;
|
private float _blueScale;
|
||||||
private SKColor _currentColor;
|
private SKColor _currentColor;
|
||||||
@ -33,11 +35,13 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
|||||||
ICoreService coreService,
|
ICoreService coreService,
|
||||||
IRgbService rgbService,
|
IRgbService rgbService,
|
||||||
IMessageService messageService,
|
IMessageService messageService,
|
||||||
|
IDialogService dialogService,
|
||||||
IModelValidator<DevicePropertiesTabViewModel> validator) : base(validator)
|
IModelValidator<DevicePropertiesTabViewModel> validator) : base(validator)
|
||||||
{
|
{
|
||||||
_coreService = coreService;
|
_coreService = coreService;
|
||||||
_rgbService = rgbService;
|
_rgbService = rgbService;
|
||||||
_messageService = messageService;
|
_messageService = messageService;
|
||||||
|
_dialogService = dialogService;
|
||||||
|
|
||||||
Device = device;
|
Device = device;
|
||||||
DisplayName = "PROPERTIES";
|
DisplayName = "PROPERTIES";
|
||||||
@ -126,6 +130,11 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SelectPhysicalLayout()
|
||||||
|
{
|
||||||
|
await _dialogService.ShowDialog<DeviceLayoutDialogViewModel>(new Dictionary<string, object> {{"device", Device}});
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Apply()
|
public async Task Apply()
|
||||||
{
|
{
|
||||||
await ValidateAsync();
|
await ValidateAsync();
|
||||||
@ -167,12 +176,21 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
|||||||
_initialGreenScale = Device.GreenScale;
|
_initialGreenScale = Device.GreenScale;
|
||||||
_initialBlueScale = Device.BlueScale;
|
_initialBlueScale = Device.BlueScale;
|
||||||
CurrentColor = SKColors.White;
|
CurrentColor = SKColors.White;
|
||||||
|
|
||||||
_coreService.FrameRendering += OnFrameRendering;
|
_coreService.FrameRendering += OnFrameRendering;
|
||||||
Device.PropertyChanged += DeviceOnPropertyChanged;
|
Device.PropertyChanged += DeviceOnPropertyChanged;
|
||||||
|
|
||||||
base.OnActivate();
|
base.OnActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnDeactivate()
|
||||||
|
{
|
||||||
|
_coreService.FrameRendering -= OnFrameRendering;
|
||||||
|
Device.PropertyChanged -= DeviceOnPropertyChanged;
|
||||||
|
|
||||||
|
base.OnDeactivate();
|
||||||
|
}
|
||||||
|
|
||||||
#region Event handlers
|
#region Event handlers
|
||||||
|
|
||||||
private void DeviceOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
private void DeviceOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
|||||||
@ -84,7 +84,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
|||||||
|
|
||||||
public void ViewProperties()
|
public void ViewProperties()
|
||||||
{
|
{
|
||||||
_windowManager.ShowDialog(_deviceDebugVmFactory.DeviceDialogViewModel(Device));
|
_windowManager.ShowWindow(_deviceDebugVmFactory.DeviceDialogViewModel(Device));
|
||||||
}
|
}
|
||||||
private async Task UpdateIsDeviceEnabled(bool value)
|
private async Task UpdateIsDeviceEnabled(bool value)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -241,7 +241,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
|||||||
|
|
||||||
public void ViewProperties(ArtemisDevice device)
|
public void ViewProperties(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
_windowManager.ShowDialog(_deviceDebugVmFactory.DeviceDialogViewModel(device));
|
_windowManager.ShowWindow(_deviceDebugVmFactory.DeviceDialogViewModel(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DetectInput(ArtemisDevice device)
|
public async Task DetectInput(ArtemisDevice device)
|
||||||
|
|||||||
80
src/Artemis.UI/Services/DeviceLayoutService.cs
Normal file
80
src/Artemis.UI/Services/DeviceLayoutService.cs
Normal file
@ -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<ArtemisDevice> _ignoredDevices;
|
||||||
|
|
||||||
|
public DeviceLayoutService(IDialogService dialogService, IRgbService rgbService, IWindowService windowService, IMessageService messageService)
|
||||||
|
{
|
||||||
|
_dialogService = dialogService;
|
||||||
|
_rgbService = rgbService;
|
||||||
|
_windowService = windowService;
|
||||||
|
_messageService = messageService;
|
||||||
|
_ignoredDevices = new List<ArtemisDevice>();
|
||||||
|
|
||||||
|
rgbService.DeviceAdded += RgbServiceOnDeviceAdded;
|
||||||
|
windowService.MainWindowOpened += async (_, _) => await RequestLayoutInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RequestLayoutInput()
|
||||||
|
{
|
||||||
|
List<ArtemisDevice> 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<DeviceLayoutDialogViewModel>(new Dictionary<string, object> {{"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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user