mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 13:28:33 +00:00
Reworked device properties screen
This commit is contained in:
parent
cdfa14441e
commit
db069ea8bf
@ -25,6 +25,7 @@ using Artemis.UI.Screens.Sidebar;
|
||||
using Artemis.UI.Screens.SurfaceEditor;
|
||||
using Artemis.UI.Screens.VisualScripting;
|
||||
using Artemis.UI.Screens.VisualScripting.Pins;
|
||||
using Artemis.UI.Shared;
|
||||
using DryIoc;
|
||||
using ReactiveUI;
|
||||
|
||||
@ -40,9 +41,11 @@ public interface IDeviceVmFactory : IVmFactory
|
||||
DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel);
|
||||
DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device);
|
||||
DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device);
|
||||
DeviceLayoutTabViewModel DeviceLayoutTabViewModel(ArtemisDevice device);
|
||||
DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device);
|
||||
DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds);
|
||||
InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds);
|
||||
DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device);
|
||||
}
|
||||
public class DeviceFactory : IDeviceVmFactory
|
||||
{
|
||||
@ -72,7 +75,12 @@ public class DeviceFactory : IDeviceVmFactory
|
||||
{
|
||||
return _container.Resolve<DevicePropertiesTabViewModel>(new object[] { device });
|
||||
}
|
||||
|
||||
|
||||
public DeviceLayoutTabViewModel DeviceLayoutTabViewModel(ArtemisDevice device)
|
||||
{
|
||||
return _container.Resolve<DeviceLayoutTabViewModel>(new object[] { device });
|
||||
}
|
||||
|
||||
public DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device)
|
||||
{
|
||||
return _container.Resolve<DeviceInfoTabViewModel>(new object[] { device });
|
||||
@ -87,6 +95,11 @@ public class DeviceFactory : IDeviceVmFactory
|
||||
{
|
||||
return _container.Resolve<InputMappingsTabViewModel>(new object[] { device, selectedLeds });
|
||||
}
|
||||
|
||||
public DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device)
|
||||
{
|
||||
return _container.Resolve<DeviceGeneralTabViewModel>(new object[] { device });
|
||||
}
|
||||
}
|
||||
|
||||
public interface ISettingsVmFactory : IVmFactory
|
||||
|
||||
@ -11,8 +11,8 @@
|
||||
Icon="/Assets/Images/Logo/application.ico"
|
||||
Title="Artemis | Device Properties"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Width="1250"
|
||||
Height="900">
|
||||
Width="1400"
|
||||
Height="800">
|
||||
<windowing:AppWindow.KeyBindings>
|
||||
<KeyBinding Gesture="Escape" Command="{CompiledBinding ClearSelectedLeds}" />
|
||||
</windowing:AppWindow.KeyBindings>
|
||||
@ -52,7 +52,7 @@
|
||||
|
||||
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" />
|
||||
|
||||
<Border Grid.Column="2" Classes="card-condensed" CornerRadius="10 0 0 0" Margin="0 10 0 0" Background="#ff323232">
|
||||
<Border Grid.Column="2" Classes="card-condensed" Margin="5" Background="#ff323232">
|
||||
<Panel>
|
||||
<TabControl ItemsSource="{CompiledBinding Tabs}" IsVisible="{CompiledBinding Tabs.Count}" Padding="12">
|
||||
<TabControl.ItemTemplate>
|
||||
|
||||
@ -64,8 +64,10 @@ public class DevicePropertiesViewModel : DialogViewModelBase<object>
|
||||
|
||||
private void AddTabs()
|
||||
{
|
||||
Tabs.Add(_deviceVmFactory.DevicePropertiesTabViewModel(Device));
|
||||
Tabs.Add(_deviceVmFactory.DeviceInfoTabViewModel(Device));
|
||||
Tabs.Add(_deviceVmFactory.DeviceGeneralTabViewModel(Device));
|
||||
Tabs.Add(_deviceVmFactory.DeviceLayoutTabViewModel(Device));
|
||||
//Tabs.Add(_deviceVmFactory.DevicePropertiesTabViewModel(Device));
|
||||
//Tabs.Add(_deviceVmFactory.DeviceInfoTabViewModel(Device));
|
||||
if (Device.DeviceType == RGBDeviceType.Keyboard)
|
||||
Tabs.Add(_deviceVmFactory.InputMappingsTabViewModel(Device, SelectedLeds));
|
||||
Tabs.Add(_deviceVmFactory.DeviceLedsTabViewModel(Device, SelectedLeds));
|
||||
|
||||
371
src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml
Normal file
371
src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml
Normal file
@ -0,0 +1,371 @@
|
||||
<UserControl 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:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="1450"
|
||||
x:Class="Artemis.UI.Screens.Device.DeviceGeneralTabView"
|
||||
x:DataType="device:DeviceGeneralTabViewModel">
|
||||
<UserControl.Resources>
|
||||
<converters:SKColorToColorConverter x:Key="SKColorToColorConverter" />
|
||||
</UserControl.Resources>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<StackPanel Grid.Row="0" Orientation="Vertical">
|
||||
<!-- Device information and categories -->
|
||||
<Grid ColumnDefinitions="*,*" RowDefinitions="*,*">
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Classes="card-title" Text="Information" Margin="10,0,0,0" />
|
||||
<Border Grid.Column="0" Grid.Row="1" Classes="card" Margin="5" x:Name="InformationBorder">
|
||||
<Grid ColumnDefinitions="*,Auto" RowDefinitions="*,*,*,*,*,*">
|
||||
<StackPanel Grid.Row="0" Grid.Column="0">
|
||||
<TextBlock Text="Model" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Model}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||
<TextBlock Text="Manufacturer" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Manufacturer}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="2" Grid.Column="0">
|
||||
<TextBlock Text="Device Type" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceType}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="3" Grid.Column="0">
|
||||
<TextBlock Text="Size (1px = 1mm)" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.Size}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="4" Grid.Column="0" IsVisible="{CompiledBinding IsKeyboard}">
|
||||
<TextBlock Text="Physical Layout" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding Device.PhysicalLayout}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="5" Grid.Column="0" IsVisible="{CompiledBinding IsKeyboard}" >
|
||||
<TextBlock Text="Logical Layout" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding Device.LogicalLayout}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Column="1" Grid.Row="0" Classes="card-title" Text="Categories" Margin="10,0,0,0" />
|
||||
<Border Grid.Row="1" Grid.Column="1" Classes="card" Margin="5" x:Name="CategoryBorder">
|
||||
<StackPanel>
|
||||
<TextBlock TextWrapping="Wrap" Text="Artemis uses categories to determine where the layers of imported profiles are applied to." />
|
||||
<Grid ColumnDefinitions="*,Auto" RowDefinitions="*,*,*,*,*" Margin="0,10,0,0">
|
||||
<StackPanel Grid.Row="0" Grid.Column="0" Margin="0,0,0,10">
|
||||
<TextBlock Text="Peripheral" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A peripheral such as a mouse or keyboard" />
|
||||
</StackPanel>
|
||||
<CheckBox Grid.Row="0" Grid.Column="1" IsChecked="{CompiledBinding HasPeripheralsCategory}" />
|
||||
|
||||
<StackPanel Grid.Row="1" Grid.Column="0" Margin="0,0,0,10">
|
||||
<TextBlock Text="Desk" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A device acting as desk ornamentation such as a LED strip" />
|
||||
</StackPanel>
|
||||
<CheckBox Grid.Row="1" Grid.Column="1" IsChecked="{CompiledBinding HasDeskCategory}" />
|
||||
|
||||
<StackPanel Grid.Row="2" Grid.Column="0" Margin="0,0,0,10">
|
||||
<TextBlock Text="Monitor" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A device attached to the monitor such as ambilight LEDs" />
|
||||
</StackPanel>
|
||||
<CheckBox Grid.Row="2" Grid.Column="1" IsChecked="{CompiledBinding HasMonitorCategory}" />
|
||||
|
||||
<StackPanel Grid.Row="3" Grid.Column="0" Margin="0,0,0,10">
|
||||
<TextBlock Text="Case" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A device inside your computer case" />
|
||||
</StackPanel>
|
||||
<CheckBox Grid.Row="3" Grid.Column="1" IsChecked="{CompiledBinding HasCaseCategory}" />
|
||||
|
||||
<StackPanel Grid.Row="4" Grid.Column="0" Margin="0,0,0,10">
|
||||
<TextBlock Text="Room" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A device elsewhere in the room" />
|
||||
</StackPanel>
|
||||
<CheckBox Grid.Row="4" Grid.Column="1" IsChecked="{CompiledBinding HasRoomCategory}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Surface and Calibration -->
|
||||
<Grid ColumnDefinitions="*,*" RowDefinitions="*,*">
|
||||
<TextBlock Grid.Column="0" Grid.Row="0" Classes="card-title" Text="Surface" Margin="10,0,0,0" />
|
||||
<Border Grid.Column="0" Grid.Row="1" Classes="card" Margin="5" x:Name="SurfaceBorder">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock TextWrapping="Wrap" Text="The device can be rotated and scaled on the surface with the values below." />
|
||||
<Grid ColumnDefinitions="*,Auto,Auto" RowDefinitions="*,*,*,*">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center">X-coordinate</TextBlock>
|
||||
<NumericUpDown Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="10 5"
|
||||
VerticalAlignment="Center"
|
||||
Value="{CompiledBinding X}" />
|
||||
<TextBlock Grid.Row="0" Grid.Column="2" VerticalAlignment="Center">mm</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center">Y-coordinate</TextBlock>
|
||||
<NumericUpDown Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="10 5"
|
||||
VerticalAlignment="Center"
|
||||
Value="{CompiledBinding Y}" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" VerticalAlignment="Center">mm</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center">Scale</TextBlock>
|
||||
<NumericUpDown Grid.Row="2"
|
||||
Grid.Column="1"
|
||||
Margin="10 5"
|
||||
VerticalAlignment="Center"
|
||||
Increment="0.1"
|
||||
FormatString="F1"
|
||||
Value="{CompiledBinding Scale}" />
|
||||
<TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">times</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center">Rotation</TextBlock>
|
||||
<NumericUpDown Grid.Row="3"
|
||||
Grid.Column="1"
|
||||
Margin="10 5"
|
||||
VerticalAlignment="Center"
|
||||
Value="{CompiledBinding Rotation}" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="2" VerticalAlignment="Center">deg</TextBlock>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<TextBlock Grid.Column="1" Grid.Row="0" Classes="card-title" Text="Calibration" Margin="10,0,0,0" />
|
||||
<Border Grid.Row="1" Grid.Column="1" Classes="card" Margin="5" x:Name="CalibrationBorder">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock TextWrapping="Wrap" Text="Use the sliders below to adjust the colors of your device so that it matches your other devices." />
|
||||
<Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="*,*,*,*">
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="R" VerticalAlignment="Center" />
|
||||
<Slider Grid.Row="0" Grid.Column="1" Minimum="0" Maximum="200" Value="{CompiledBinding RedScale}" Margin="10 0" VerticalAlignment="Center" />
|
||||
<NumericUpDown Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Width="65"
|
||||
Value="{CompiledBinding RedScale}"
|
||||
ShowButtonSpinner="False"
|
||||
FormatString="{}{0:0.0}"
|
||||
Minimum="0"
|
||||
Maximum="200"
|
||||
ClipValueToMinMax="True" />
|
||||
|
||||
<Label Grid.Row="1" Grid.Column="0" Content="G" VerticalAlignment="Center" />
|
||||
<Slider Grid.Row="1" Grid.Column="1" Minimum="0" Maximum="200" Value="{CompiledBinding GreenScale}" Margin="10 0" VerticalAlignment="Center" />
|
||||
<NumericUpDown Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Width="65"
|
||||
Value="{CompiledBinding GreenScale}"
|
||||
ShowButtonSpinner="False"
|
||||
FormatString="{}{0:0.0}"
|
||||
Minimum="0"
|
||||
Maximum="200"
|
||||
ClipValueToMinMax="True" />
|
||||
|
||||
<Label Grid.Row="2" Grid.Column="0" Content="B" VerticalAlignment="Center" />
|
||||
<Slider Grid.Row="2" Grid.Column="1" Minimum="0" Maximum="200" Value="{CompiledBinding BlueScale}" Margin="10 0" Ticks="100" VerticalAlignment="Center" />
|
||||
<NumericUpDown Grid.Row="2"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Width="65"
|
||||
Value="{CompiledBinding BlueScale}"
|
||||
ShowButtonSpinner="False"
|
||||
FormatString="{}{0:0.0}"
|
||||
Minimum="0"
|
||||
Maximum="200"
|
||||
ClipValueToMinMax="True" />
|
||||
|
||||
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" IsChecked="{CompiledBinding DisplayOnDevices}" Content="Show preview" VerticalAlignment="Center" />
|
||||
<controls:ColorPickerButton Grid.Row="3"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Color="{CompiledBinding CurrentColor, Converter={StaticResource SKColorToColorConverter}}"
|
||||
ShowAcceptDismissButtons="False" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Stacked instead of grid here: -->
|
||||
<!-- <StackPanel Grid.Row="0"> -->
|
||||
<!-- <TextBlock Classes="card-title" Text="Information" Margin="10,0,0,0" /> -->
|
||||
<!-- <Border Classes="card" Margin="5" x:Name="InformationBorder"> -->
|
||||
<!-- <Grid ColumnDefinitions="*,Auto" RowDefinitions="*,*,*,*,*,*"> -->
|
||||
<!-- <TextBlock Grid.Column="0" Grid.Row="0" Text="Model" /> -->
|
||||
<!-- <TextBlock Grid.Column="1" Grid.Row="0" Classes="subtitle" TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Model}" /> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Grid.Column="0" Grid.Row="1" Text="Manufacturer" /> -->
|
||||
<!-- <TextBlock Grid.Column="1" Grid.Row="1" Classes="subtitle" TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Manufacturer}" /> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Grid.Column="0" Grid.Row="2" Text="Device Type" /> -->
|
||||
<!-- <TextBlock Grid.Column="1" Grid.Row="2" Classes="subtitle" TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceType}" /> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Grid.Column="0" Grid.Row="3" Text="Size (1px = 1mm)" /> -->
|
||||
<!-- <TextBlock Grid.Column="1" Grid.Row="3" Classes="subtitle" TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.Size}" /> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock IsVisible="{CompiledBinding IsKeyboard}" Grid.Column="0" Grid.Row="4" Text="Physical Layout" /> -->
|
||||
<!-- <TextBlock IsVisible="{CompiledBinding IsKeyboard}" Grid.Column="1" Grid.Row="4" Classes="subtitle" TextWrapping="Wrap" Text="{CompiledBinding Device.PhysicalLayout}" /> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock IsVisible="{CompiledBinding IsKeyboard}" Grid.Column="0" Grid.Row="5" Text="Logical Layout" /> -->
|
||||
<!-- <TextBlock IsVisible="{CompiledBinding IsKeyboard}" Grid.Column="1" Grid.Row="5" Classes="subtitle" TextWrapping="Wrap" Text="{CompiledBinding Device.LogicalLayout}" /> -->
|
||||
<!-- </Grid> -->
|
||||
<!-- </Border> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Classes="card-title" Text="Categories" Margin="10,0,0,0" /> -->
|
||||
<!-- <Border Classes="card" Margin="5" x:Name="CategoryBorder"> -->
|
||||
<!-- <StackPanel> -->
|
||||
<!-- <TextBlock TextWrapping="Wrap" Text="Artemis uses categories to determine where the layers of imported profiles are applied to." /> -->
|
||||
<!-- <Grid ColumnDefinitions="*,Auto" RowDefinitions="*,*,*,*,*" Margin="0,10,0,0"> -->
|
||||
<!-- <StackPanel Grid.Row="0" Grid.Column="0" Margin="0,0,0,10"> -->
|
||||
<!-- <TextBlock Text="Peripheral" /> -->
|
||||
<!-- <TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A peripheral such as a mouse or keyboard" /> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- <CheckBox Grid.Row="0" Grid.Column="1" IsChecked="{CompiledBinding HasPeripheralsCategory}" /> -->
|
||||
<!-- -->
|
||||
<!-- <StackPanel Grid.Row="1" Grid.Column="0" Margin="0,0,0,10"> -->
|
||||
<!-- <TextBlock Text="Desk" /> -->
|
||||
<!-- <TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A device acting as desk ornamentation such as a LED strip" /> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- <CheckBox Grid.Row="1" Grid.Column="1" IsChecked="{CompiledBinding HasDeskCategory}" /> -->
|
||||
<!-- -->
|
||||
<!-- <StackPanel Grid.Row="2" Grid.Column="0" Margin="0,0,0,10"> -->
|
||||
<!-- <TextBlock Text="Monitor" /> -->
|
||||
<!-- <TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A device attached to the monitor such as ambilight LEDs" /> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- <CheckBox Grid.Row="2" Grid.Column="1" IsChecked="{CompiledBinding HasMonitorCategory}" /> -->
|
||||
<!-- -->
|
||||
<!-- <StackPanel Grid.Row="3" Grid.Column="0" Margin="0,0,0,10"> -->
|
||||
<!-- <TextBlock Text="Case" /> -->
|
||||
<!-- <TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A device inside your computer case" /> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- <CheckBox Grid.Row="3" Grid.Column="1" IsChecked="{CompiledBinding HasCaseCategory}" /> -->
|
||||
<!-- -->
|
||||
<!-- <StackPanel Grid.Row="4" Grid.Column="0" Margin="0,0,0,10"> -->
|
||||
<!-- <TextBlock Text="Room" /> -->
|
||||
<!-- <TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="A device elsewhere in the room" /> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- <CheckBox Grid.Row="4" Grid.Column="1" IsChecked="{CompiledBinding HasRoomCategory}" /> -->
|
||||
<!-- </Grid> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- </Border> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Classes="card-title" Text="Surface" Margin="10,0,0,0" /> -->
|
||||
<!-- <Border Classes="card" Margin="5" x:Name="SurfaceBorder"> -->
|
||||
<!-- <StackPanel Orientation="Vertical"> -->
|
||||
<!-- <TextBlock TextWrapping="Wrap" Text="The device can be rotated and scaled on the surface with the values below." /> -->
|
||||
<!-- <Grid ColumnDefinitions="*,Auto,Auto" RowDefinitions="*,*,*,*"> -->
|
||||
<!-- <TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center">X-coordinate</TextBlock> -->
|
||||
<!-- <NumericUpDown Grid.Row="0" -->
|
||||
<!-- Grid.Column="1" -->
|
||||
<!-- Margin="10 5" -->
|
||||
<!-- VerticalAlignment="Center" -->
|
||||
<!-- Value="{CompiledBinding X}" /> -->
|
||||
<!-- <TextBlock Grid.Row="0" Grid.Column="2" VerticalAlignment="Center">mm</TextBlock> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center">Y-coordinate</TextBlock> -->
|
||||
<!-- <NumericUpDown Grid.Row="1" -->
|
||||
<!-- Grid.Column="1" -->
|
||||
<!-- Margin="10 5" -->
|
||||
<!-- VerticalAlignment="Center" -->
|
||||
<!-- Value="{CompiledBinding Y}" /> -->
|
||||
<!-- <TextBlock Grid.Row="1" Grid.Column="2" VerticalAlignment="Center">mm</TextBlock> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Grid.Row="2" Grid.Column="0" VerticalAlignment="Center">Scale</TextBlock> -->
|
||||
<!-- <NumericUpDown Grid.Row="2" -->
|
||||
<!-- Grid.Column="1" -->
|
||||
<!-- Margin="10 5" -->
|
||||
<!-- VerticalAlignment="Center" -->
|
||||
<!-- Increment="0.1" -->
|
||||
<!-- FormatString="F1" -->
|
||||
<!-- Value="{CompiledBinding Scale}" /> -->
|
||||
<!-- <TextBlock Grid.Row="2" Grid.Column="2" VerticalAlignment="Center">times</TextBlock> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center">Rotation</TextBlock> -->
|
||||
<!-- <NumericUpDown Grid.Row="3" -->
|
||||
<!-- Grid.Column="1" -->
|
||||
<!-- Margin="10 5" -->
|
||||
<!-- VerticalAlignment="Center" -->
|
||||
<!-- Value="{CompiledBinding Rotation}" /> -->
|
||||
<!-- <TextBlock Grid.Row="3" Grid.Column="2" VerticalAlignment="Center">deg</TextBlock> -->
|
||||
<!-- </Grid> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- </Border> -->
|
||||
<!-- -->
|
||||
<!-- <TextBlock Classes="card-title" Text="Calibration" Margin="10,0,0,0" /> -->
|
||||
<!-- <Border Classes="card" Margin="5" x:Name="CalibrationBorder"> -->
|
||||
<!-- <StackPanel Orientation="Vertical"> -->
|
||||
<!-- <TextBlock TextWrapping="Wrap" Text="Use the sliders below to adjust the colors of your device so that it matches your other devices." /> -->
|
||||
<!-- <Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="*,*,*,*"> -->
|
||||
<!-- <Label Grid.Row="0" Grid.Column="0" Content="R" VerticalAlignment="Center" /> -->
|
||||
<!-- <Slider Grid.Row="0" Grid.Column="1" Minimum="0" Maximum="200" Value="{CompiledBinding RedScale}" Margin="10 0" VerticalAlignment="Center" /> -->
|
||||
<!-- <NumericUpDown Grid.Row="0" -->
|
||||
<!-- Grid.Column="2" -->
|
||||
<!-- VerticalAlignment="Center" -->
|
||||
<!-- Width="65" -->
|
||||
<!-- Value="{CompiledBinding RedScale}" -->
|
||||
<!-- ShowButtonSpinner="False" -->
|
||||
<!-- FormatString="{}{0:0.0}" -->
|
||||
<!-- Minimum="0" -->
|
||||
<!-- Maximum="200" -->
|
||||
<!-- ClipValueToMinMax="True" /> -->
|
||||
<!-- -->
|
||||
<!-- <Label Grid.Row="1" Grid.Column="0" Content="G" VerticalAlignment="Center" /> -->
|
||||
<!-- <Slider Grid.Row="1" Grid.Column="1" Minimum="0" Maximum="200" Value="{CompiledBinding GreenScale}" Margin="10 0" VerticalAlignment="Center" /> -->
|
||||
<!-- <NumericUpDown Grid.Row="1" -->
|
||||
<!-- Grid.Column="2" -->
|
||||
<!-- VerticalAlignment="Center" -->
|
||||
<!-- Width="65" -->
|
||||
<!-- Value="{CompiledBinding GreenScale}" -->
|
||||
<!-- ShowButtonSpinner="False" -->
|
||||
<!-- FormatString="{}{0:0.0}" -->
|
||||
<!-- Minimum="0" -->
|
||||
<!-- Maximum="200" -->
|
||||
<!-- ClipValueToMinMax="True" /> -->
|
||||
<!-- -->
|
||||
<!-- <Label Grid.Row="2" Grid.Column="0" Content="B" VerticalAlignment="Center" /> -->
|
||||
<!-- <Slider Grid.Row="2" Grid.Column="1" Minimum="0" Maximum="200" Value="{CompiledBinding BlueScale}" Margin="10 0" Ticks="100" VerticalAlignment="Center" /> -->
|
||||
<!-- <NumericUpDown Grid.Row="2" -->
|
||||
<!-- Grid.Column="2" -->
|
||||
<!-- VerticalAlignment="Center" -->
|
||||
<!-- Width="65" -->
|
||||
<!-- Value="{CompiledBinding BlueScale}" -->
|
||||
<!-- ShowButtonSpinner="False" -->
|
||||
<!-- FormatString="{}{0:0.0}" -->
|
||||
<!-- Minimum="0" -->
|
||||
<!-- Maximum="200" -->
|
||||
<!-- ClipValueToMinMax="True" /> -->
|
||||
<!-- -->
|
||||
<!-- <CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" IsChecked="{CompiledBinding DisplayOnDevices}" Content="Show preview" VerticalAlignment="Center" /> -->
|
||||
<!-- <controls:ColorPickerButton Grid.Row="3" -->
|
||||
<!-- Grid.Column="2" -->
|
||||
<!-- VerticalAlignment="Center" -->
|
||||
<!-- HorizontalAlignment="Right" -->
|
||||
<!-- Color="{CompiledBinding CurrentColor, Converter={StaticResource SKColorToColorConverter}}" -->
|
||||
<!-- ShowAcceptDismissButtons="False" /> -->
|
||||
<!-- </Grid> -->
|
||||
<!-- </StackPanel> -->
|
||||
<!-- </Border> -->
|
||||
<!-- </StackPanel> -->
|
||||
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,*" Margin="5">
|
||||
<Button Grid.Column="0"
|
||||
IsVisible="{CompiledBinding RequiresManualSetup}"
|
||||
Command="{CompiledBinding RestartSetup}"
|
||||
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 IsCancel="True" Command="{CompiledBinding Reset}" Margin="0 0 5 0" Content="Reset" />
|
||||
<Button Classes="accent" IsDefault="True" Command="{CompiledBinding Apply}" Content="Apply" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@ -0,0 +1,11 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Device;
|
||||
public partial class DeviceGeneralTabView : ReactiveUserControl<DeviceGeneralTabViewModel>
|
||||
{
|
||||
public DeviceGeneralTabView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
256
src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabViewModel.cs
Normal file
256
src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabViewModel.cs
Normal file
@ -0,0 +1,256 @@
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using ReactiveUI;
|
||||
using RGB.NET.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.UI.Screens.Device;
|
||||
public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IRgbService _rgbService;
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly List<DeviceCategory> _categories;
|
||||
|
||||
private readonly float _initialBlueScale;
|
||||
private readonly float _initialGreenScale;
|
||||
private readonly float _initialRedScale;
|
||||
|
||||
private int _rotation;
|
||||
private float _scale;
|
||||
private int _x;
|
||||
private int _y;
|
||||
|
||||
private float _redScale;
|
||||
private float _greenScale;
|
||||
private float _blueScale;
|
||||
private SKColor _currentColor;
|
||||
private bool _displayOnDevices;
|
||||
|
||||
public DeviceGeneralTabViewModel(ArtemisDevice device, ICoreService coreService, IRgbService rgbService, IWindowService windowService)
|
||||
{
|
||||
_coreService = coreService;
|
||||
_rgbService = rgbService;
|
||||
_windowService = windowService;
|
||||
_categories = new List<DeviceCategory>(device.Categories);
|
||||
|
||||
Device = device;
|
||||
DisplayName = "General";
|
||||
X = (int) Device.X;
|
||||
Y = (int) Device.Y;
|
||||
Scale = Device.Scale;
|
||||
Rotation = (int) Device.Rotation;
|
||||
RedScale = Device.RedScale * 100f;
|
||||
GreenScale = Device.GreenScale * 100f;
|
||||
BlueScale = Device.BlueScale * 100f;
|
||||
CurrentColor = SKColors.White;
|
||||
|
||||
// We need to store the initial values to be able to restore them when the user clicks "Cancel"
|
||||
_initialRedScale = Device.RedScale;
|
||||
_initialGreenScale = Device.GreenScale;
|
||||
_initialBlueScale = Device.BlueScale;
|
||||
|
||||
this.WhenAnyValue(x => x.RedScale, x => x.GreenScale, x => x.BlueScale).Subscribe(_ => ApplyScaling());
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
Device.PropertyChanged += DeviceOnPropertyChanged;
|
||||
_coreService.FrameRendering += OnFrameRendering;
|
||||
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
_coreService.FrameRendering -= OnFrameRendering;
|
||||
Device.PropertyChanged -= DeviceOnPropertyChanged;
|
||||
}).DisposeWith(d);
|
||||
});
|
||||
}
|
||||
|
||||
public bool RequiresManualSetup => !Device.DeviceProvider.CanDetectPhysicalLayout || !Device.DeviceProvider.CanDetectLogicalLayout;
|
||||
|
||||
public ArtemisDevice Device { get; }
|
||||
|
||||
public int X
|
||||
{
|
||||
get => _x;
|
||||
set => RaiseAndSetIfChanged(ref _x, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => _y;
|
||||
set => RaiseAndSetIfChanged(ref _y, value);
|
||||
}
|
||||
|
||||
public float Scale
|
||||
{
|
||||
get => _scale;
|
||||
set => RaiseAndSetIfChanged(ref _scale, value);
|
||||
}
|
||||
|
||||
public int Rotation
|
||||
{
|
||||
get => _rotation;
|
||||
set => RaiseAndSetIfChanged(ref _rotation, value);
|
||||
}
|
||||
|
||||
public bool IsKeyboard => Device.DeviceType == RGBDeviceType.Keyboard;
|
||||
|
||||
public bool HasDeskCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Desk);
|
||||
set => SetCategory(DeviceCategory.Desk, value);
|
||||
}
|
||||
|
||||
public bool HasMonitorCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Monitor);
|
||||
set => SetCategory(DeviceCategory.Monitor, value);
|
||||
}
|
||||
|
||||
public bool HasCaseCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Case);
|
||||
set => SetCategory(DeviceCategory.Case, value);
|
||||
}
|
||||
|
||||
public bool HasRoomCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Room);
|
||||
set => SetCategory(DeviceCategory.Room, value);
|
||||
}
|
||||
|
||||
public bool HasPeripheralsCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Peripherals);
|
||||
set => SetCategory(DeviceCategory.Peripherals, value);
|
||||
}
|
||||
|
||||
public float RedScale
|
||||
{
|
||||
get => _redScale;
|
||||
set => RaiseAndSetIfChanged(ref _redScale, value);
|
||||
}
|
||||
|
||||
public float GreenScale
|
||||
{
|
||||
get => _greenScale;
|
||||
set => RaiseAndSetIfChanged(ref _greenScale, value);
|
||||
}
|
||||
|
||||
public float BlueScale
|
||||
{
|
||||
get => _blueScale;
|
||||
set => RaiseAndSetIfChanged(ref _blueScale, value);
|
||||
}
|
||||
|
||||
public SKColor CurrentColor
|
||||
{
|
||||
get => _currentColor;
|
||||
set => RaiseAndSetIfChanged(ref _currentColor, value);
|
||||
}
|
||||
|
||||
public bool DisplayOnDevices
|
||||
{
|
||||
get => _displayOnDevices;
|
||||
set => RaiseAndSetIfChanged(ref _displayOnDevices, value);
|
||||
}
|
||||
|
||||
public void ApplyScaling()
|
||||
{
|
||||
Device.RedScale = RedScale / 100f;
|
||||
Device.GreenScale = GreenScale / 100f;
|
||||
Device.BlueScale = BlueScale / 100f;
|
||||
|
||||
_rgbService.FlushLeds = true;
|
||||
}
|
||||
|
||||
private bool GetCategory(DeviceCategory category)
|
||||
{
|
||||
return _categories.Contains(category);
|
||||
}
|
||||
|
||||
private void SetCategory(DeviceCategory category, bool value)
|
||||
{
|
||||
if (value && !_categories.Contains(category))
|
||||
_categories.Add(category);
|
||||
else if (!value)
|
||||
_categories.Remove(category);
|
||||
|
||||
this.RaisePropertyChanged($"Has{category}Category");
|
||||
}
|
||||
|
||||
public async Task RestartSetup()
|
||||
{
|
||||
if (!RequiresManualSetup)
|
||||
return;
|
||||
if (!Device.DeviceProvider.CanDetectPhysicalLayout && !await DevicePhysicalLayoutDialogViewModel.SelectPhysicalLayout(_windowService, Device))
|
||||
return;
|
||||
if (!Device.DeviceProvider.CanDetectLogicalLayout && !await DeviceLogicalLayoutDialogViewModel.SelectLogicalLayout(_windowService, Device))
|
||||
return;
|
||||
|
||||
await Task.Delay(400);
|
||||
_rgbService.SaveDevice(Device);
|
||||
_rgbService.ApplyBestDeviceLayout(Device);
|
||||
}
|
||||
|
||||
public async Task Apply()
|
||||
{
|
||||
// TODO: Validation
|
||||
|
||||
_coreService.ProfileRenderingDisabled = true;
|
||||
await Task.Delay(100);
|
||||
|
||||
Device.X = X;
|
||||
Device.Y = Y;
|
||||
Device.Scale = Scale;
|
||||
Device.Rotation = Rotation;
|
||||
Device.RedScale = RedScale / 100f;
|
||||
Device.GreenScale = GreenScale / 100f;
|
||||
Device.BlueScale = BlueScale / 100f;
|
||||
Device.Categories.Clear();
|
||||
foreach (DeviceCategory deviceCategory in _categories)
|
||||
Device.Categories.Add(deviceCategory);
|
||||
|
||||
_rgbService.SaveDevice(Device);
|
||||
|
||||
_coreService.ProfileRenderingDisabled = false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
HasDeskCategory = Device.Categories.Contains(DeviceCategory.Desk);
|
||||
HasMonitorCategory = Device.Categories.Contains(DeviceCategory.Monitor);
|
||||
HasCaseCategory = Device.Categories.Contains(DeviceCategory.Case);
|
||||
HasRoomCategory = Device.Categories.Contains(DeviceCategory.Room);
|
||||
HasPeripheralsCategory = Device.Categories.Contains(DeviceCategory.Peripherals);
|
||||
|
||||
RedScale = _initialRedScale * 100;
|
||||
GreenScale = _initialGreenScale * 100;
|
||||
BlueScale = _initialBlueScale * 100;
|
||||
}
|
||||
|
||||
private void OnFrameRendering(object? sender, FrameRenderingEventArgs e)
|
||||
{
|
||||
if (!DisplayOnDevices)
|
||||
return;
|
||||
|
||||
using SKPaint overlayPaint = new() {Color = CurrentColor};
|
||||
e.Canvas.DrawRect(0, 0, e.Canvas.LocalClipBounds.Width, e.Canvas.LocalClipBounds.Height, overlayPaint);
|
||||
}
|
||||
|
||||
private void DeviceOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(Device.CustomLayoutPath) || e.PropertyName == nameof(Device.DisableDefaultLayout))
|
||||
Task.Run(() => _rgbService.ApplyBestDeviceLayout(Device));
|
||||
}
|
||||
}
|
||||
82
src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabView.axaml
Normal file
82
src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabView.axaml
Normal file
@ -0,0 +1,82 @@
|
||||
<UserControl 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:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800"
|
||||
x:Class="Artemis.UI.Screens.Device.DeviceLayoutTabView"
|
||||
x:DataType="device:DeviceLayoutTabViewModel">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<Border Classes="card" Margin="5">
|
||||
<Grid RowDefinitions="*,Auto">
|
||||
<StackPanel Grid.Row="0">
|
||||
<TextBlock
|
||||
TextWrapping="Wrap"
|
||||
Text="The device layout is used to determine the position of LEDs and to create the visual representation of the device." />
|
||||
<Grid ColumnDefinitions="*,Auto" RowDefinitions="*,*,*,*,*" Margin="0, 20,0,0">
|
||||
<StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="0,0,0,10" >
|
||||
<TextBlock Text="Default layout file path" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding DefaultLayoutPath}" />
|
||||
</StackPanel>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
Classes="icon-button"
|
||||
HorizontalAlignment="Right"
|
||||
ToolTip.Tip="Copy layout file path to clipboard"
|
||||
Click="LayoutPathButton_OnClick">
|
||||
<avalonia:MaterialIcon Kind="ContentCopy" Width="18" Height="18" />
|
||||
</Button>
|
||||
|
||||
<StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,0,0,10">
|
||||
<TextBlock Text="Image file path" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" TextWrapping="Wrap" Text="{CompiledBinding Device.Layout.Image.LocalPath}" />
|
||||
</StackPanel>
|
||||
<Button
|
||||
Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Classes="icon-button"
|
||||
HorizontalAlignment="Right"
|
||||
ToolTip.Tip="Copy image file path to clipboard"
|
||||
Click="ImagePathButton_OnClick">
|
||||
<avalonia:MaterialIcon Kind="ContentCopy" Width="18" Height="18" />
|
||||
</Button>
|
||||
|
||||
<StackPanel Grid.Column="0" Grid.Row="2" Margin="0,0,0,10">
|
||||
<TextBlock Text="Disable default layout" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" Text="With this checked, Artemis will not load a layout for this device unless you specifically provide one." />
|
||||
</StackPanel>
|
||||
<CheckBox Grid.Column="1" Grid.Row="2" HorizontalAlignment="Right" Margin="0,0,-10,0" />
|
||||
|
||||
<StackPanel Grid.Column="0" Grid.Row="3" Margin="0,0,0,10">
|
||||
<TextBlock Text="Custom layout path" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" Text="{CompiledBinding CustomLayoutPath}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="Clear" Command="{CompiledBinding ClearCustomLayout}" IsEnabled="{CompiledBinding HasCustomLayout}" />
|
||||
<!-- 5 pixels of margin between the buttons -->
|
||||
<Button Margin="5,0,0,0" Content="Browse" Command="{CompiledBinding BrowseCustomLayout}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="0" Grid.Row="4" Margin="0,0,0,10">
|
||||
<TextBlock Text="Export current layout" />
|
||||
<TextBlock Classes="subtitle" FontSize="12" Text="If there is a layout used, export that. Otherwise, export the LEDs present." />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="1" Grid.Row="4" Margin="0,0,0,0" HorizontalAlignment="Right" Content="Export" Command="{CompiledBinding ExportLayout}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<controls:HyperlinkButton
|
||||
Content="Learn more about layouts on the wiki"
|
||||
NavigateUri="https://wiki.artemis-rgb.com/en/guides/developer/layouts"
|
||||
Grid.Row="1"
|
||||
Margin="0 20"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom" />
|
||||
</Grid>
|
||||
|
||||
</Border>
|
||||
|
||||
</ScrollViewer>
|
||||
</UserControl>
|
||||
@ -0,0 +1,26 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Device;
|
||||
|
||||
public partial class DeviceLayoutTabView : ReactiveUserControl<DeviceLayoutTabViewModel>
|
||||
{
|
||||
public DeviceLayoutTabView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void LayoutPathButton_OnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
TopLevel.GetTopLevel(this).Clipboard.SetTextAsync(ViewModel.DefaultLayoutPath);
|
||||
}
|
||||
|
||||
private void ImagePathButton_OnClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
TopLevel.GetTopLevel(this).Clipboard.SetTextAsync(ViewModel.Device.Layout.Image.LocalPath);
|
||||
}
|
||||
}
|
||||
143
src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabViewModel.cs
Normal file
143
src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabViewModel.cs
Normal file
@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Artemis.UI.Shared.Services.Builders;
|
||||
using Avalonia.Controls;
|
||||
using ReactiveUI;
|
||||
using RGB.NET.Layout;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.UI.Screens.Device;
|
||||
|
||||
public class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
||||
{
|
||||
private readonly IWindowService _windowService;
|
||||
private readonly INotificationService _notificationService;
|
||||
|
||||
public DeviceLayoutTabViewModel(
|
||||
IWindowService windowService,
|
||||
INotificationService notificationService,
|
||||
ArtemisDevice device)
|
||||
{
|
||||
_windowService = windowService;
|
||||
_notificationService = notificationService;
|
||||
|
||||
Device = device;
|
||||
DisplayName = "Layout";
|
||||
DefaultLayoutPath = Device.DeviceProvider.LoadLayout(Device).FilePath;
|
||||
}
|
||||
|
||||
public ArtemisDevice Device { get; }
|
||||
|
||||
public string DefaultLayoutPath { get; }
|
||||
|
||||
public string CustomLayoutPath => Device.CustomLayoutPath ?? "None";
|
||||
|
||||
public bool HasCustomLayout => Device.CustomLayoutPath != null;
|
||||
|
||||
private void RaiseCustomLayoutChanged()
|
||||
{
|
||||
this.RaisePropertyChanged(nameof(CustomLayoutPath));
|
||||
this.RaisePropertyChanged(nameof(HasCustomLayout));
|
||||
}
|
||||
|
||||
public void ClearCustomLayout()
|
||||
{
|
||||
Device.CustomLayoutPath = null;
|
||||
_notificationService.CreateNotification()
|
||||
.WithMessage("Cleared imported layout.")
|
||||
.WithSeverity(NotificationSeverity.Informational);
|
||||
|
||||
RaiseCustomLayoutChanged();
|
||||
}
|
||||
|
||||
public async Task BrowseCustomLayout()
|
||||
{
|
||||
string[]? files = await _windowService.CreateOpenFileDialog()
|
||||
.WithTitle("Select device layout file")
|
||||
.HavingFilter(f => f.WithName("Layout files").WithExtension("xml"))
|
||||
.ShowAsync();
|
||||
|
||||
if (files?.Length > 0)
|
||||
{
|
||||
Device.CustomLayoutPath = files[0];
|
||||
_notificationService.CreateNotification()
|
||||
.WithTitle("Imported layout")
|
||||
.WithMessage($"File loaded from {files[0]}")
|
||||
.WithSeverity(NotificationSeverity.Informational);
|
||||
}
|
||||
|
||||
RaiseCustomLayoutChanged();
|
||||
}
|
||||
|
||||
public async Task ExportLayout()
|
||||
{
|
||||
string fileName = Device.DeviceProvider.GetDeviceLayoutName(Device);
|
||||
string layoutDir = Constants.LayoutsFolder;
|
||||
string filePath = Path.Combine(
|
||||
layoutDir,
|
||||
Device.RgbDevice.DeviceInfo.Manufacturer,
|
||||
Device.DeviceType.ToString(),
|
||||
fileName
|
||||
);
|
||||
if (!Directory.Exists(filePath))
|
||||
Directory.CreateDirectory(filePath);
|
||||
|
||||
string? result = await _windowService.CreateSaveFileDialog()
|
||||
.HavingFilter(f => f.WithExtension("xml").WithName("Artemis layout"))
|
||||
.WithDirectory(filePath)
|
||||
.WithInitialFileName(fileName)
|
||||
.ShowAsync();
|
||||
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
ArtemisLayout? layout = Device.Layout;
|
||||
if (layout?.IsValid == true)
|
||||
{
|
||||
string path = layout.FilePath;
|
||||
File.Copy(path, result, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<LedLayout> ledLayouts = Device.Leds.Select(x => new LedLayout()
|
||||
{
|
||||
Id = x.RgbLed.Id.ToString(),
|
||||
DescriptiveX = x.Rectangle.Left.ToString(),
|
||||
DescriptiveY = x.Rectangle.Top.ToString(),
|
||||
DescriptiveWidth = $"{x.Rectangle.Width}mm",
|
||||
DescriptiveHeight = $"{x.Rectangle.Height}mm",
|
||||
}).ToList();
|
||||
|
||||
DeviceLayout emptyLayout = new()
|
||||
{
|
||||
Author = "Artemis",
|
||||
Type = Device.DeviceType,
|
||||
Vendor = Device.RgbDevice.DeviceInfo.Manufacturer,
|
||||
Model = Device.RgbDevice.DeviceInfo.Model,
|
||||
Width = Device.Rectangle.Width,
|
||||
Height = Device.Rectangle.Height,
|
||||
InternalLeds = ledLayouts,
|
||||
};
|
||||
|
||||
XmlSerializer serializer = new(typeof(DeviceLayout));
|
||||
await using StreamWriter writer = new(result);
|
||||
serializer.Serialize(writer, emptyLayout);
|
||||
}
|
||||
|
||||
_notificationService.CreateNotification()
|
||||
.WithMessage("Layout exported")
|
||||
.WithTimeout(TimeSpan.FromSeconds(5))
|
||||
.WithSeverity(NotificationSeverity.Success)
|
||||
.Show();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user