Devices - Added custom layout loading

This commit is contained in:
Robert committed 2021-02-19 16:42:09 +01:00
1 parent 056b2bface
commit b154badd9c
21 files changed
+414 -110

No files matched your search

@@ -179,7 +179,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
base.OnClose();
}
private void RgbServiceOnDevicesModified(object? sender, DeviceEventArgs e)
private void RgbServiceOnDevicesModified(object sender, DeviceEventArgs e)
{
ApplyDevices();
}
@@ -40,9 +40,31 @@
</Button>
<materialDesign:PopupBox PlacementMode="BottomAndAlignRightEdges" StaysOpen="False">
<StackPanel>
<Button Content="Open plugin directory" Command="{s:Action OpenPluginDirectory}" />
<Button Content="Open image directory" Command="{s:Action OpenImageDirectory}" />
<Button Content="Reload layout" Command="{s:Action ReloadLayout}" />
<Button Command="{s:Action OpenPluginDirectory}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Plugin" Margin="0 0 10 0 " VerticalAlignment="Center" />
<TextBlock VerticalAlignment="Center">Open plugin directory</TextBlock>
</StackPanel>
</Button>
<Button Command="{s:Action OpenImageDirectory}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Image" Margin="0 0 10 0 " VerticalAlignment="Center" />
<TextBlock VerticalAlignment="Center">Open layout image directory</TextBlock>
</StackPanel>
</Button>
<Separator />
<Button Command="{s:Action ReloadLayout}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Reload" Margin="0 0 10 0 " VerticalAlignment="Center" />
<TextBlock VerticalAlignment="Center">Reload layout</TextBlock>
</StackPanel>
</Button>
<Button Command="{s:Action ExportLayout}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Xml" Margin="0 0 10 0 " VerticalAlignment="Center" />
<TextBlock VerticalAlignment="Center">Export layout</TextBlock>
</StackPanel>
</Button>
</StackPanel>
</materialDesign:PopupBox>
</StackPanel>
@@ -56,12 +78,12 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock TextWrapping="Wrap" Margin="0 0 00 10">
<TextBlock TextWrapping="Wrap" Margin="0 0 0 10">
In this window you can view detailed information of the device.
Please note that having this window open can have a performance impact on your system.
</TextBlock>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="1" Padding="15">
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="1" Padding="15" Margin="0 10">
<shared:DeviceVisualizer Device="{Binding Device}"
HighlightedLeds="{Binding SelectedLeds}"
HorizontalAlignment="Center"
@@ -69,14 +91,14 @@
ShowColors="True" />
</materialDesign:Card>
<Expander Grid.Row="2" VerticalAlignment="Center" Header="Device properties" Margin="0 15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<materialDesign:Card Grid.Column="0" materialDesign:ShadowAssist.ShadowDepth="Depth1" Margin="0,0,5,0">
<StackPanel Margin="15" HorizontalAlignment="Stretch">
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" Grid.Row="2" Padding="15" Margin="0 10">
<Expander VerticalAlignment="Center" Header="Device properties">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="15" HorizontalAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
@@ -93,7 +115,7 @@
Text="{Binding Device.RgbDevice.DeviceInfo.DeviceName}" />
</StackPanel>
</Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="0 5" />
<Grid>
<Grid.RowDefinitions>
@@ -111,7 +133,7 @@
Text="{Binding Device.RgbDevice.DeviceInfo.Manufacturer}" />
</StackPanel>
</Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="0 5" />
<Grid>
<Grid.RowDefinitions>
@@ -129,7 +151,7 @@
Text="{Binding Device.RgbDevice.DeviceInfo.DeviceType}" />
</StackPanel>
</Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="0 5" />
<Grid>
<Grid.RowDefinitions>
@@ -147,7 +169,7 @@
Text="{Binding Device.PhysicalLayout}" />
</StackPanel>
</Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="0 5" />
<Grid>
<Grid.RowDefinitions>
@@ -166,9 +188,7 @@
</StackPanel>
</Grid>
</StackPanel>
</materialDesign:Card>
<materialDesign:Card Grid.Column="1" materialDesign:ShadowAssist.ShadowDepth="Depth1" Margin="5,0,0,0">
<StackPanel Margin="15" HorizontalAlignment="Stretch">
<StackPanel Grid.Column="1" Margin="15" HorizontalAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
@@ -185,7 +205,7 @@
Text="{Binding Device.RgbDevice.Size}" />
</StackPanel>
</Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="0 5" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
@@ -202,7 +222,7 @@
Text="{Binding Device.RgbDevice.Location}" />
</StackPanel>
</Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="0 5" />
<Grid>
<Grid.RowDefinitions>
@@ -220,7 +240,7 @@
Text="{Binding Device.RgbDevice.Rotation.Degrees}" />
</StackPanel>
</Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="0 5" />
<Grid>
<Grid.RowDefinitions>
@@ -238,7 +258,7 @@
Text="{Binding Device.LogicalLayout}" />
</StackPanel>
</Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="0 5" />
<Grid>
<Grid.RowDefinitions>
@@ -257,11 +277,11 @@
</StackPanel>
</Grid>
</StackPanel>
</materialDesign:Card>
</Grid>
</Expander>
</Grid>
</Expander>
</materialDesign:Card>
<materialDesign:Card Grid.Row="3" materialDesign:ShadowAssist.ShadowDepth="Depth1" Padding="15" MaxHeight="413">
<materialDesign:Card Grid.Row="3" materialDesign:ShadowAssist.ShadowDepth="Depth1" Padding="15" MaxHeight="413" Margin="0 10">
<DataGrid ItemsSource="{Binding Device.Leds}"
d:DataContext="{d:DesignInstance Type=core:ArtemisLed}"
CanUserSortColumns="True"
@@ -2,18 +2,23 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Xml.Serialization;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared.Services;
using Stylet; // using PropertyChanged;
using Ookii.Dialogs.Wpf;
using RGB.NET.Layout;
using Stylet;
// using PropertyChanged;
namespace Artemis.UI.Screens.Settings.Debug
{
public class DeviceDebugViewModel : Screen
{
private readonly IDeviceService _deviceService;
private readonly IRgbService _rgbService;
private readonly IDialogService _dialogService;
private readonly IRgbService _rgbService;
private ArtemisLed _selectedLed;
public DeviceDebugViewModel(ArtemisDevice device, IDeviceService deviceService, IRgbService rgbService, IDialogService dialogService)
@@ -81,13 +86,69 @@ namespace Artemis.UI.Screens.Settings.Debug
}
public void ReloadLayout()
{
_rgbService.ApplyBestDeviceLayout(Device);
}
public void ExportLayout()
{
if (Device.Layout == null)
_rgbService.ApplyBestDeviceLayout(Device);
else
return;
VistaFolderBrowserDialog dialog = new()
{
Device.Layout.ReloadFromDisk();
_rgbService.ApplyDeviceLayout(Device, Device.Layout);
Description = "Select layout export target folder",
UseDescriptionForTitle = true,
ShowNewFolderButton = true,
SelectedPath = Path.Combine(Constants.DataFolder, "user layouts")
};
bool? result = dialog.ShowDialog();
if (result != true)
return;
string directory = Path.Combine(
dialog.SelectedPath,
Device.RgbDevice.DeviceInfo.Manufacturer,
Device.RgbDevice.DeviceInfo.DeviceType.ToString()
);
string filePath = Path.Combine(directory, Device.GetLayoutFileName());
Core.Utilities.CreateAccessibleDirectory(directory);
// XML
XmlSerializer serializer = new(typeof(DeviceLayout));
using StreamWriter writer = new(filePath);
serializer.Serialize(writer, Device.Layout!.RgbLayout);
// Device images
if (!Uri.IsWellFormedUriString(Device.Layout.FilePath, UriKind.Absolute))
return;
Uri targetDirectory = new(directory + "/", UriKind.Absolute);
Uri sourceDirectory = new(Path.GetDirectoryName(Device.Layout.FilePath)! + "/", UriKind.Absolute);
Uri deviceImageTarget = new(targetDirectory, Device.Layout.LayoutCustomDeviceData.DeviceImage);
// Create folder (if needed) and copy image
Core.Utilities.CreateAccessibleDirectory(Path.GetDirectoryName(deviceImageTarget.LocalPath)!);
if (Device.Layout.Image != null && File.Exists(Device.Layout.Image.LocalPath) && !File.Exists(deviceImageTarget.LocalPath))
File.Copy(Device.Layout.Image.LocalPath, deviceImageTarget.LocalPath);
foreach (ArtemisLedLayout ledLayout in Device.Layout.Leds)
{
if (ledLayout.LayoutCustomLedData.LogicalLayouts == null)
continue;
// Only the image of the current logical layout is available as an URI, iterate each layout and find the images manually
foreach (LayoutCustomLedDataLogicalLayout logicalLayout in ledLayout.LayoutCustomLedData.LogicalLayouts)
{
Uri image = new(sourceDirectory, logicalLayout.Image);
Uri imageTarget = new(targetDirectory, logicalLayout.Image);
// Create folder (if needed) and copy image
Core.Utilities.CreateAccessibleDirectory(Path.GetDirectoryName(imageTarget.LocalPath)!);
if (File.Exists(image.LocalPath) && !File.Exists(imageTarget.LocalPath))
File.Copy(image.LocalPath, imageTarget.LocalPath);
}
}
}
@@ -76,7 +76,7 @@
<Button Command="{s:Action ViewProperties}">
<StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Kind="Gear" Margin="0 0 10 0 " VerticalAlignment="Center" />
<TextBlock VerticalAlignment="Center">View surface properties</TextBlock>
<TextBlock VerticalAlignment="Center">Device properties</TextBlock>
</StackPanel>
</Button>
</StackPanel>
@@ -57,6 +57,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
// Take it off the UI thread to avoid freezing on tab change
Task.Run(async () =>
{
Items.Clear();
await Task.Delay(200);
_instances = _pluginManagementService.GetAllPlugins()
.Select(p => _settingsVmFactory.CreatePluginSettingsViewModel(p))
@@ -155,12 +155,39 @@
<shared:ColorPicker Grid.Column="1"
Margin="0,0,5,0"
HorizontalAlignment="Right"
Color="{Binding CurrentColor, Converter={StaticResource SKColorToColorConverter}}"
VerticalAlignment="Center"/>
Color="{Binding CurrentColor, Converter={StaticResource SKColorToColorConverter}}"
VerticalAlignment="Center" />
</Grid>
</Grid>
</Grid>
<!-- Layout -->
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Margin="0 25 0 0">
Custom layout
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignCaptionTextBlock}"
Foreground="{DynamicResource MaterialDesignBodyLight}"
TextWrapping="Wrap"
TextAlignment="Justify">
Select a custom layout below if you want to change the appearance and/or LEDs of this device.
</TextBlock>
<TextBox Style="{StaticResource MaterialDesignFloatingHintTextBox}"
Text="{Binding Device.CustomLayoutPath}"
VerticalAlignment="Center"
materialDesign:TextFieldAssist.HasClearButton="True"
IsReadOnly="True"
PreviewMouseLeftButtonUp="{s:Action BrowseCustomLayout}">
<materialDesign:HintAssist.Hint>
<StackPanel Orientation="Horizontal" Margin="-2 0 0 0">
<materialDesign:PackIcon Kind="Xml" Width="20" />
<TextBlock>
Layout path
</TextBlock>
</StackPanel>
</materialDesign:HintAssist.Hint>
</TextBox>
<!-- Buttons -->
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right">
@@ -1,7 +1,12 @@
using System.Threading.Tasks;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared.Services;
using MaterialDesignThemes.Wpf;
using Ookii.Dialogs.Wpf;
using SkiaSharp;
using Stylet;
@@ -10,6 +15,8 @@ namespace Artemis.UI.Screens.SurfaceEditor.Dialogs
public class SurfaceDeviceConfigViewModel : DialogViewModelBase
{
private readonly ICoreService _coreService;
private readonly IRgbService _rgbService;
private readonly IMessageService _messageService;
private readonly double _initialRedScale;
private readonly double _initialGreenScale;
private readonly double _initialBlueScale;
@@ -23,41 +30,43 @@ namespace Artemis.UI.Screens.SurfaceEditor.Dialogs
private SKColor _currentColor;
private bool _displayOnDevices;
public SurfaceDeviceConfigViewModel(ArtemisDevice device, ICoreService coreService, IModelValidator<SurfaceDeviceConfigViewModel> validator) : base(validator)
public SurfaceDeviceConfigViewModel(ArtemisDevice device,
ICoreService coreService,
IRgbService rgbService,
IMessageService messageService,
IModelValidator<SurfaceDeviceConfigViewModel> validator) : base(validator)
{
_coreService = coreService;
_rgbService = rgbService;
_messageService = messageService;
Device = device;
X = (int)Device.X;
Y = (int)Device.Y;
X = (int) Device.X;
Y = (int) Device.Y;
Scale = Device.Scale;
Rotation = (int)Device.Rotation;
Rotation = (int) Device.Rotation;
RedScale = Device.RedScale * 100d;
GreenScale = Device.GreenScale * 100d;
BlueScale = Device.BlueScale * 100d;
//we need to store the initial values to be able to restore them when the user clicks "Cancel"
_initialRedScale = Device.RedScale;
_initialRedScale = Device.RedScale;
_initialGreenScale = Device.GreenScale;
_initialBlueScale = Device.BlueScale;
CurrentColor = SKColors.White;
_coreService.FrameRendering += OnFrameRendering;
}
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);
Device.PropertyChanged += DeviceOnPropertyChanged;
}
public ArtemisDevice Device { get; }
public override void OnDialogClosed(object sender, DialogClosingEventArgs e)
{
_coreService.FrameRendering -= OnFrameRendering;
Device.PropertyChanged -= DeviceOnPropertyChanged;
base.OnDialogClosed(sender, e);
}
public int X
{
get => _x;
@@ -130,7 +139,6 @@ namespace Artemis.UI.Screens.SurfaceEditor.Dialogs
Device.BlueScale = BlueScale / 100d;
_coreService.ModuleRenderingDisabled = false;
_coreService.FrameRendering -= OnFrameRendering;
Session.Close(true);
}
@@ -141,6 +149,26 @@ namespace Artemis.UI.Screens.SurfaceEditor.Dialogs
Device.BlueScale = BlueScale / 100d;
}
public void BrowseCustomLayout(object sender, MouseEventArgs e)
{
if (e.OriginalSource is Button)
{
Device.CustomLayoutPath = null;
_messageService.ShowMessage("Cleared imported layout");
return;
}
VistaOpenFileDialog dialog = new();
dialog.Filter = "Layout files (*.xml)|*.xml";
dialog.Title = "Select device layout file";
bool? result = dialog.ShowDialog();
if (result == true)
{
Device.CustomLayoutPath = dialog.FileName;
_messageService.ShowMessage($"Imported layout from {dialog.FileName}");
}
}
public override void Cancel()
{
Device.RedScale = _initialRedScale;
@@ -149,5 +177,25 @@ namespace Artemis.UI.Screens.SurfaceEditor.Dialogs
base.Cancel();
}
private void DeviceOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Device.CustomLayoutPath))
{
_rgbService.ApplyBestDeviceLayout(Device);
}
}
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);
}
}
}
@@ -16,6 +16,7 @@ using Artemis.UI.Screens.SurfaceEditor.Dialogs;
using Artemis.UI.Screens.SurfaceEditor.Visualization;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using SkiaSharp;
using Stylet;
using MouseButton = System.Windows.Input.MouseButton;
@@ -27,13 +28,16 @@ namespace Artemis.UI.Screens.SurfaceEditor
private readonly IInputService _inputService;
private readonly IDialogService _dialogService;
private readonly IRgbService _rgbService;
private readonly ICoreService _coreService;
private readonly ISettingsService _settingsService;
private Cursor _cursor;
private PanZoomViewModel _panZoomViewModel;
private RectangleGeometry _selectionRectangle;
private PluginSetting<GridLength> _surfaceListWidth;
private List<ArtemisDevice> _shuffledDevices;
public SurfaceEditorViewModel(IRgbService rgbService,
ICoreService coreService,
IDialogService dialogService,
ISettingsService settingsService,
IDeviceService deviceService,
@@ -48,6 +52,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
ListDeviceViewModels = new BindableCollection<ListDeviceViewModel>();
_rgbService = rgbService;
_coreService = coreService;
_dialogService = dialogService;
_settingsService = settingsService;
_deviceService = deviceService;
@@ -105,6 +110,22 @@ namespace Artemis.UI.Screens.SurfaceEditor
SurfaceListWidth.Save();
}
private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e)
{
float amount = 360f / _shuffledDevices.Count;
for (int i = 0; i < _shuffledDevices.Count; i++)
{
ArtemisDevice rgbServiceDevice = _shuffledDevices[i];
foreach (ArtemisLed artemisLed in rgbServiceDevice.Leds)
{
SKColor color = SKColor.FromHsv(amount * i, 100, 100);
e.Canvas.DrawRect(artemisLed.AbsoluteRectangle, new SKPaint(){Color = color});
}
}
}
#region Overrides of Screen
protected override void OnInitialActivate()
@@ -112,6 +133,10 @@ namespace Artemis.UI.Screens.SurfaceEditor
LoadWorkspaceSettings();
SurfaceDeviceViewModels.AddRange(_rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => new SurfaceDeviceViewModel(d, _rgbService)));
ListDeviceViewModels.AddRange(_rgbService.EnabledDevices.OrderBy(d => d.ZIndex * -1).Select(d => new ListDeviceViewModel(d)));
_shuffledDevices = _rgbService.EnabledDevices.OrderBy(d => Guid.NewGuid()).ToList();
_coreService.FrameRendering += CoreServiceOnFrameRendering;
base.OnInitialActivate();
}
@@ -120,6 +145,9 @@ namespace Artemis.UI.Screens.SurfaceEditor
SaveWorkspaceSettings();
SurfaceDeviceViewModels.Clear();
ListDeviceViewModels.Clear();
_coreService.FrameRendering -= CoreServiceOnFrameRendering;
base.OnClose();
}
@@ -14,6 +14,10 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<shared:DeviceVisualizer Device="{Binding Device}" Width="30" Height="30" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBlock Text="{Binding Device.RgbDevice.DeviceInfo.DeviceName}" Grid.Column="1" VerticalAlignment="Center" />
<StackPanel Grid.Column="1" VerticalAlignment="Center" >
<TextBlock Text="{Binding Device.RgbDevice.DeviceInfo.Model}" />
<TextBlock Text="{Binding Device.RgbDevice.DeviceInfo.Manufacturer}" Foreground="{DynamicResource MaterialDesignBodyLight}" />
</StackPanel>
</Grid>
</UserControl>