diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
index 9f39a9864..90aee62a2 100644
--- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
+++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
@@ -249,6 +249,20 @@ namespace Artemis.Core
}
}
+ ///
+ /// Gets or sets the path of the custom layout to load when calling
+ /// for this device
+ ///
+ public string? CustomLayoutPath
+ {
+ get => DeviceEntity.CustomLayoutPath;
+ set
+ {
+ DeviceEntity.CustomLayoutPath = value;
+ OnPropertyChanged(nameof(CustomLayoutPath));
+ }
+ }
+
///
/// Gets the layout of the device expanded with Artemis-specific data
///
@@ -304,10 +318,12 @@ namespace Artemis.Core
/// Applies the provided layout to the device
///
/// The layout to apply
- internal void ApplyLayout(ArtemisLayout layout)
+ /// A boolean indicating whether to add missing LEDs defined in the layout but missing on the device
+ /// A boolean indicating whether to remove excess LEDs present in the device but missing in the layout
+ internal void ApplyLayout(ArtemisLayout layout, bool createMissingLeds, bool removeExcessiveLeds)
{
if (layout.IsValid)
- layout.RgbLayout!.ApplyTo(RgbDevice);
+ layout.RgbLayout!.ApplyTo(RgbDevice, createMissingLeds, removeExcessiveLeds);
Leds = RgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
LedIds = new ReadOnlyDictionary(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
diff --git a/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs b/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
index 672594b9a..cc837ca3b 100644
--- a/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
+++ b/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
@@ -15,9 +15,11 @@ namespace Artemis.Core
/// Creates a new instance of the class
///
/// The path of the layout XML file
- public ArtemisLayout(string filePath)
+ /// The source from where this layout is being loaded
+ public ArtemisLayout(string filePath, LayoutSource source)
{
FilePath = filePath;
+ Source = source;
Leds = new List();
LoadLayout();
@@ -29,9 +31,9 @@ namespace Artemis.Core
public string FilePath { get; }
///
- /// Gets the RGB.NET device layout
+ /// Gets the source from where this layout was loaded
///
- public DeviceLayout RgbLayout { get; private set; }
+ public LayoutSource Source { get; }
///
/// Gets the device this layout is applied to
@@ -48,9 +50,20 @@ namespace Artemis.Core
///
public Uri? Image { get; private set; }
+ ///
+ /// Gets a list of LEDs this layout contains
+ ///
public List Leds { get; }
- internal LayoutCustomDeviceData LayoutCustomDeviceData { get; set; }
+ ///
+ /// Gets the RGB.NET device layout
+ ///
+ public DeviceLayout RgbLayout { get; private set; } = null!;
+
+ ///
+ /// Gets the custom layout data embedded in the RGB.NET layout
+ ///
+ public LayoutCustomDeviceData LayoutCustomDeviceData { get; private set; } = null!;
public void ReloadFromDisk()
{
@@ -88,11 +101,43 @@ namespace Artemis.Core
private void ApplyCustomDeviceData()
{
- Uri layoutDirectory = new(Path.GetDirectoryName(FilePath)! + "\\", UriKind.Absolute);
+ if (!IsValid)
+ {
+ Image = null;
+ return;
+ }
+
+ Uri layoutDirectory = new(Path.GetDirectoryName(FilePath)! + "/", UriKind.Absolute);
if (LayoutCustomDeviceData.DeviceImage != null)
Image = new Uri(layoutDirectory, new Uri(LayoutCustomDeviceData.DeviceImage, UriKind.Relative));
else
Image = null;
}
}
+
+ ///
+ /// Represents a source from where a layout came
+ ///
+ public enum LayoutSource
+ {
+ ///
+ /// A layout loaded from config
+ ///
+ Configured,
+
+ ///
+ /// A layout loaded from the user layout folder
+ ///
+ User,
+
+ ///
+ /// A layout loaded from the plugin folder
+ ///
+ Plugin,
+
+ ///
+ /// A default layout loaded as a fallback option
+ ///
+ Default
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/Surface/Layout/ArtemisLedLayout.cs b/src/Artemis.Core/Models/Surface/Layout/ArtemisLedLayout.cs
index 28bee2d41..e0ee9fa07 100644
--- a/src/Artemis.Core/Models/Surface/Layout/ArtemisLedLayout.cs
+++ b/src/Artemis.Core/Models/Surface/Layout/ArtemisLedLayout.cs
@@ -39,7 +39,10 @@ namespace Artemis.Core
///
public Uri? Image { get; private set; }
- internal LayoutCustomLedData LayoutCustomLedData { get; set; }
+ ///
+ /// Gets the custom layout data embedded in the RGB.NET layout
+ ///
+ public LayoutCustomLedData LayoutCustomLedData { get; }
internal void ApplyDevice(ArtemisDevice device)
{
diff --git a/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs b/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs
index 838a5a87a..dd3d7ad5b 100644
--- a/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs
+++ b/src/Artemis.Core/Plugins/DeviceProviders/DeviceProvider.cs
@@ -60,18 +60,35 @@ namespace Artemis.Core.DeviceProviders
///
/// Loads a layout for the specified device and wraps it in an
///
- /// The device to load the layout for
+ /// The device to load the layout for
/// The resulting Artemis layout
- public virtual ArtemisLayout LoadLayout(ArtemisDevice rgbDevice)
+ public virtual ArtemisLayout LoadLayout(ArtemisDevice device)
{
string layoutDir = Path.Combine(Plugin.Directory.FullName, "Layouts");
string filePath = Path.Combine(
layoutDir,
- rgbDevice.RgbDevice.DeviceInfo.Manufacturer,
- rgbDevice.RgbDevice.DeviceInfo.DeviceType.ToString(),
- rgbDevice.GetLayoutFileName()
+ device.RgbDevice.DeviceInfo.Manufacturer,
+ device.RgbDevice.DeviceInfo.DeviceType.ToString(),
+ device.GetLayoutFileName()
);
- return new ArtemisLayout(filePath);
+ return new ArtemisLayout(filePath, LayoutSource.Plugin);
+ }
+
+ ///
+ /// Loads a layout from the user layout folder for the specified device and wraps it in an
+ ///
+ /// The device to load the layout for
+ /// The resulting Artemis layout
+ public virtual ArtemisLayout LoadUserLayout(ArtemisDevice device)
+ {
+ string layoutDir = Path.Combine(Constants.DataFolder, "user layouts");
+ string filePath = Path.Combine(
+ layoutDir,
+ device.RgbDevice.DeviceInfo.Manufacturer,
+ device.RgbDevice.DeviceInfo.DeviceType.ToString(),
+ device.GetLayoutFileName()
+ );
+ return new ArtemisLayout(filePath, LayoutSource.User);
}
///
diff --git a/src/Artemis.Core/Services/Interfaces/IRgbService.cs b/src/Artemis.Core/Services/Interfaces/IRgbService.cs
index 3009ecccc..838f15ff8 100644
--- a/src/Artemis.Core/Services/Interfaces/IRgbService.cs
+++ b/src/Artemis.Core/Services/Interfaces/IRgbService.cs
@@ -74,7 +74,9 @@ namespace Artemis.Core.Services
///
///
///
- void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout layout);
+ ///
+ ///
+ void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout layout, bool createMissingLeds, bool removeExessiveLeds);
///
/// Attempts to retrieve the that corresponds the provided RGB.NET
diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs
index 30e8d79f0..31dc0070c 100644
--- a/src/Artemis.Core/Services/PluginManagementService.cs
+++ b/src/Artemis.Core/Services/PluginManagementService.cs
@@ -9,7 +9,6 @@ using Artemis.Core.DeviceProviders;
using Artemis.Core.Ninject;
using Artemis.Storage.Entities.Plugins;
using Artemis.Storage.Repositories.Interfaces;
-using Humanizer;
using McMaster.NETCore.Plugins;
using Ninject;
using Ninject.Extensions.ChildKernel;
@@ -147,7 +146,7 @@ namespace Artemis.Core.Services
// TODO: move to a more appropriate service
public DeviceProvider GetDeviceProviderByDevice(IRGBDevice rgbDevice)
{
- return GetFeaturesOfType().First(d => d.RgbDeviceProvider.Devices != null && d.RgbDeviceProvider.Devices.Contains(rgbDevice));
+ return GetFeaturesOfType().First(d => d.RgbDeviceProvider.Devices.Contains(rgbDevice));
}
public Plugin? GetCallingPlugin()
@@ -186,7 +185,6 @@ namespace Artemis.Core.Services
// Load the plugin assemblies into the plugin context
DirectoryInfo pluginDirectory = new(Path.Combine(Constants.DataFolder, "plugins"));
foreach (DirectoryInfo subDirectory in pluginDirectory.EnumerateDirectories())
- {
try
{
LoadPlugin(subDirectory);
@@ -195,7 +193,6 @@ namespace Artemis.Core.Services
{
_logger.Warning(new ArtemisPluginException("Failed to load plugin", e), "Plugin exception");
}
- }
// ReSharper disable InconsistentlySynchronizedField - It's read-only, idc
_logger.Debug("Loaded {count} plugin(s)", _plugins.Count);
@@ -338,7 +335,6 @@ namespace Artemis.Core.Services
// Create instances of each feature and add them to the plugin
// Construction should be simple and not contain any logic so failure at this point means the entire plugin fails
foreach (Type featureType in featureTypes)
- {
try
{
plugin.Kernel.Bind(featureType).ToSelf().InSingletonScope();
@@ -360,11 +356,9 @@ namespace Artemis.Core.Services
{
_logger.Warning(new ArtemisPluginException(plugin, "Failed to instantiate feature", e), "Failed to instantiate feature", plugin);
}
- }
// Activate plugins after they are all loaded
foreach (PluginFeature pluginFeature in plugin.Features.Where(i => i.Entity.IsEnabled))
- {
try
{
EnablePluginFeature(pluginFeature, false, !ignorePluginLock);
@@ -373,7 +367,6 @@ namespace Artemis.Core.Services
{
// ignored, logged in EnablePluginFeature
}
- }
if (saveState)
{
@@ -474,13 +467,11 @@ namespace Artemis.Core.Services
Directory.CreateDirectory(directoryInfo.FullName);
string metaDataDirectory = metaDataFileEntry.FullName.Replace(metaDataFileEntry.Name, "");
foreach (ZipArchiveEntry zipArchiveEntry in archive.Entries)
- {
if (zipArchiveEntry.FullName.StartsWith(metaDataDirectory))
{
string target = Path.Combine(directoryInfo.FullName, zipArchiveEntry.FullName.Remove(0, metaDataDirectory.Length));
zipArchiveEntry.ExtractToFile(target);
}
- }
// Load the newly extracted plugin and return the result
return LoadPlugin(directoryInfo);
@@ -563,10 +554,8 @@ namespace Artemis.Core.Services
private void SavePlugin(Plugin plugin)
{
foreach (PluginFeature pluginFeature in plugin.Features)
- {
if (plugin.Entity.Features.All(i => i.Type != pluginFeature.GetType().FullName))
plugin.Entity.Features.Add(pluginFeature.Entity);
- }
_pluginRepository.SavePlugin(plugin.Entity);
}
diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs
index a494e34eb..3cec517d6 100644
--- a/src/Artemis.Core/Services/RgbService.cs
+++ b/src/Artemis.Core/Services/RgbService.cs
@@ -191,26 +191,53 @@ namespace Artemis.Core.Services
public ArtemisLayout ApplyBestDeviceLayout(ArtemisDevice device)
{
- // Look for a user layout
- // ... here
+ ArtemisLayout layout;
- // Try loading a device provider layout, if that comes back valid we use that
- ArtemisLayout layout = device.DeviceProvider.LoadLayout(device);
+ // Configured layout path takes precedence over all other options
+ if (device.CustomLayoutPath != null)
+ {
+ layout = new ArtemisLayout(device.CustomLayoutPath, LayoutSource.Configured);
+ if (layout.IsValid)
+ {
+ ApplyDeviceLayout(device, layout, true, true);
+ return layout;
+ }
+ }
+
+ // Look for a layout provided by the user
+ layout = device.DeviceProvider.LoadUserLayout(device);
+ if (layout.IsValid)
+ {
+ ApplyDeviceLayout(device, layout, true, true);
+ return layout;
+ }
+
+ // Look for a layout provided by the plugin
+ layout = device.DeviceProvider.LoadLayout(device);
+ if (layout.IsValid)
+ {
+ ApplyDeviceLayout(device, layout, true, true);
+ return layout;
+ }
// Finally fall back to a default layout
- // .. do it!
-
- ApplyDeviceLayout(device, layout);
+ layout = LoadDefaultLayout(device);
+ ApplyDeviceLayout(device, layout, true, true);
return layout;
}
- public void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout layout)
+ private ArtemisLayout LoadDefaultLayout(ArtemisDevice device)
{
- device.ApplyLayout(layout);
+ return new ArtemisLayout("NYI", LayoutSource.Default);
+ }
+
+ public void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout layout, bool createMissingLeds, bool removeExessiveLeds)
+ {
+ device.ApplyLayout(layout, createMissingLeds, removeExessiveLeds);
// Applying layouts can affect LEDs, update LED group
UpdateBitmapBrush();
}
-
+
public ArtemisDevice? GetDevice(IRGBDevice rgbDevice)
{
return _devices.FirstOrDefault(d => d.RgbDevice == rgbDevice);
diff --git a/src/Artemis.Core/Utilities/Utilities.cs b/src/Artemis.Core/Utilities/Utilities.cs
index 9d7e7de8e..8577185bc 100644
--- a/src/Artemis.Core/Utilities/Utilities.cs
+++ b/src/Artemis.Core/Utilities/Utilities.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -18,8 +17,9 @@ namespace Artemis.Core
///
public static void PrepareFirstLaunch()
{
- CreateArtemisFolderIfMissing(Constants.DataFolder);
- CreateArtemisFolderIfMissing(Constants.DataFolder + "plugins");
+ CreateAccessibleDirectory(Constants.DataFolder);
+ CreateAccessibleDirectory(Constants.DataFolder + "plugins");
+ CreateAccessibleDirectory(Constants.DataFolder + "user layouts");
}
///
@@ -62,15 +62,11 @@ namespace Artemis.Core
}
///
- /// Gets the current application location
+ /// Creates all directories and subdirectories in the specified path unless they already exist with permissions
+ /// allowing access by everyone.
///
- ///
- internal static string GetCurrentLocation()
- {
- return Process.GetCurrentProcess().MainModule!.FileName!;
- }
-
- private static void CreateArtemisFolderIfMissing(string path)
+ /// The directory to create.
+ public static void CreateAccessibleDirectory(string path)
{
if (!Directory.Exists(path))
{
@@ -92,6 +88,15 @@ namespace Artemis.Core
}
}
+ ///
+ /// Gets the current application location
+ ///
+ ///
+ internal static string GetCurrentLocation()
+ {
+ return Process.GetCurrentProcess().MainModule!.FileName!;
+ }
+
private static void OnRestartRequested(RestartEventArgs e)
{
RestartRequested?.Invoke(null, e);
diff --git a/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs b/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs
index 142786138..670cec969 100644
--- a/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs
+++ b/src/Artemis.Storage/Entities/Surface/DeviceEntity.cs
@@ -22,8 +22,10 @@ namespace Artemis.Storage.Entities.Surface
public int PhysicalLayout { get; set; }
public string LogicalLayout { get; set; }
-
+ public string CustomLayoutPath { get; set; }
+
public List InputIdentifiers { get; set; }
+
}
public class DeviceInputIdentifierEntity
diff --git a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
index a7ce6b3d1..397dd2dae 100644
--- a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
+++ b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
@@ -286,7 +286,7 @@ namespace Artemis.UI.Shared
InvalidateMeasure();
}
- private void DeviceUpdated(object sender, EventArgs e)
+ private void DeviceUpdated(object? sender, EventArgs e)
{
SetupForDevice();
}
diff --git a/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs b/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs
index 7c6af66b1..c3ba1fd6a 100644
--- a/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs
+++ b/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs
@@ -12,6 +12,7 @@ namespace Artemis.UI.Shared
internal class DeviceVisualizerLed
{
private SolidColorBrush? _renderColorBrush;
+ private Color _renderColor;
public DeviceVisualizerLed(ArtemisLed led)
{
@@ -40,13 +41,18 @@ namespace Artemis.UI.Shared
if (DisplayGeometry == null)
return;
+ _renderColorBrush ??= new SolidColorBrush();
+
RGB.NET.Core.Color originalColor = Led.GetOriginalColor();
byte r = originalColor.GetR();
byte g = originalColor.GetG();
byte b = originalColor.GetB();
- _renderColorBrush ??= new SolidColorBrush();
- _renderColorBrush.Color = isDimmed ? Color.FromArgb(100, r, g, b) : Color.FromRgb(r, g, b);
+ _renderColor.A = isDimmed ? 100 : 255;
+ _renderColor.R = r;
+ _renderColor.G = g;
+ _renderColor.B = b;
+ _renderColorBrush.Color = _renderColor;
drawingContext.DrawRectangle(_renderColorBrush, null, LedRect);
}
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index 55ecf0e3a..a78e9658a 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -65,6 +65,9 @@
..\..\..\RGB.NET\bin\net5.0\RGB.NET.Groups.dll
+
+ ..\..\..\RGB.NET\bin\net5.0\RGB.NET.Layout.dll
+
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs
index 9fae16063..071884dcd 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Visualization/ProfileViewModel.cs
@@ -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();
}
diff --git a/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugView.xaml b/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugView.xaml
index ba1a04987..80dc57da4 100644
--- a/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Debug/DeviceDebugView.xaml
@@ -40,9 +40,31 @@
-
-
-
+
+
+
+
+
@@ -56,12 +78,12 @@
-
+
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.
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -93,7 +115,7 @@
Text="{Binding Device.RgbDevice.DeviceInfo.DeviceName}" />
-
+
@@ -111,7 +133,7 @@
Text="{Binding Device.RgbDevice.DeviceInfo.Manufacturer}" />
-
+
@@ -129,7 +151,7 @@
Text="{Binding Device.RgbDevice.DeviceInfo.DeviceType}" />
-
+
@@ -147,7 +169,7 @@
Text="{Binding Device.PhysicalLayout}" />
-
+
@@ -166,9 +188,7 @@
-
-
-
+
@@ -185,7 +205,7 @@
Text="{Binding Device.RgbDevice.Size}" />
-
+
@@ -202,7 +222,7 @@
Text="{Binding Device.RgbDevice.Location}" />
-
+
@@ -220,7 +240,7 @@
Text="{Binding Device.RgbDevice.Rotation.Degrees}" />
-
+
@@ -238,7 +258,7 @@
Text="{Binding Device.LogicalLayout}" />
-
+
@@ -257,11 +277,11 @@
-
-
-
+
+
+
-
+
- View surface properties
+ Device properties
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs
index 57f54847c..5d17a2c72 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs
@@ -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))
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigView.xaml b/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigView.xaml
index 52b34bab4..561b259f7 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigView.xaml
+++ b/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigView.xaml
@@ -155,12 +155,39 @@
+ Color="{Binding CurrentColor, Converter={StaticResource SKColorToColorConverter}}"
+ VerticalAlignment="Center" />
+
+
+ Custom layout
+
+
+ Select a custom layout below if you want to change the appearance and/or LEDs of this device.
+
+
+
+
+
+
+
+ Layout path
+
+
+
+
+
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigViewModel.cs
index 8d96c2147..ad06f0ca0 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigViewModel.cs
+++ b/src/Artemis.UI/Screens/SurfaceEditor/Dialogs/SurfaceDeviceConfigViewModel.cs
@@ -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 validator) : base(validator)
+ public SurfaceDeviceConfigViewModel(ArtemisDevice device,
+ ICoreService coreService,
+ IRgbService rgbService,
+ IMessageService messageService,
+ IModelValidator 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);
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
index d736c5f0c..714002c0d 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
+++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
@@ -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 _surfaceListWidth;
+ private List _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();
_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();
}
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/Visualization/ListDeviceView.xaml b/src/Artemis.UI/Screens/SurfaceEditor/Visualization/ListDeviceView.xaml
index c2fa66ce8..97a252739 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/Visualization/ListDeviceView.xaml
+++ b/src/Artemis.UI/Screens/SurfaceEditor/Visualization/ListDeviceView.xaml
@@ -14,6 +14,10 @@
-
+
+
+
+
+
\ No newline at end of file