From 8777e8975f0caad5c4e1da8968c73dc0879e05c9 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Wed, 30 Oct 2019 23:20:06 +0100 Subject: [PATCH] Added a layer of abstraction between RGB.NET and Artemis This means Artemis can add extra functionality It also avoid having to reference RGB.NET for basic rendering Implemented rendering scaling --- src/Artemis.Core/Artemis.Core.csproj | 9 +- .../Events/DeviceConfigurationEventArgs.cs | 6 +- .../Extensions/RgbDeviceExtensions.cs | 20 +++ src/Artemis.Core/Models/Profile/Folder.cs | 2 +- .../Profile/Interfaces/IProfileElement.cs | 2 +- src/Artemis.Core/Models/Profile/Layer.cs | 3 +- src/Artemis.Core/Models/Profile/Profile.cs | 2 +- src/Artemis.Core/Models/Surface/Device.cs | 105 ++++++++++++ src/Artemis.Core/Models/Surface/Led.cs | 38 +++++ src/Artemis.Core/Models/Surface/Surface.cs | 93 +++++++++++ .../Models/Surface/SurfaceConfiguration.cs | 58 ------- .../Surface/SurfaceDeviceConfiguration.cs | 105 ------------ src/Artemis.Core/Ninject/CoreModule.cs | 13 +- .../Ninject/SettingsServiceProvider.cs | 30 ++++ .../Plugins/Abstract/LayerType.cs | 3 +- src/Artemis.Core/Plugins/Abstract/Module.cs | 3 +- .../Plugins/Abstract/ProfileModule.cs | 3 +- .../Plugins/Models/PluginSetting.cs | 23 ++- .../Plugins/Models/PluginSettings.cs | 30 +++- src/Artemis.Core/Services/CoreService.cs | 8 +- .../Services/Interfaces/IArtemisService.cs | 3 + .../Interfaces/IProtectedArtemisService.cs | 9 + src/Artemis.Core/Services/PluginService.cs | 2 +- src/Artemis.Core/Services/RgbService.cs | 47 +++--- src/Artemis.Core/Services/SettingsService.cs | 52 ++++++ .../Services/Storage/ISurfaceService.cs | 32 ++-- .../Services/Storage/SurfaceService.cs | 157 +++++++++--------- .../BrushLayerType.cs | 3 +- .../GeneralModule.cs | 25 ++- ...rfacePositionEntity.cs => DeviceEntity.cs} | 13 +- src/Artemis.Storage/Entities/SurfaceEntity.cs | 7 +- ... 20191028171528_InitialCreate.Designer.cs} | 64 ++++--- ...ate.cs => 20191028171528_InitialCreate.cs} | 29 ++-- .../Migrations/StorageContextModelSnapshot.cs | 62 ++++--- .../Repositories/SurfaceRepository.cs | 8 +- .../SurfaceEditor/SurfaceDeviceViewModel.cs | 26 +-- .../ViewModels/Screens/SettingsViewModel.cs | 3 +- .../Screens/SurfaceEditorViewModel.cs | 38 ++--- .../SurfaceEditor/SurfaceDeviceView.xaml | 10 +- .../Views/Screens/SettingsView.xaml | 65 ++++---- .../Views/Screens/SurfaceEditorView.xaml | 8 +- 41 files changed, 725 insertions(+), 494 deletions(-) create mode 100644 src/Artemis.Core/Extensions/RgbDeviceExtensions.cs create mode 100644 src/Artemis.Core/Models/Surface/Device.cs create mode 100644 src/Artemis.Core/Models/Surface/Led.cs create mode 100644 src/Artemis.Core/Models/Surface/Surface.cs delete mode 100644 src/Artemis.Core/Models/Surface/SurfaceConfiguration.cs delete mode 100644 src/Artemis.Core/Models/Surface/SurfaceDeviceConfiguration.cs create mode 100644 src/Artemis.Core/Ninject/SettingsServiceProvider.cs create mode 100644 src/Artemis.Core/Services/Interfaces/IProtectedArtemisService.cs create mode 100644 src/Artemis.Core/Services/SettingsService.cs rename src/Artemis.Storage/Entities/{SurfacePositionEntity.cs => DeviceEntity.cs} (64%) rename src/Artemis.Storage/Migrations/{20191013153102_InitialCreate.Designer.cs => 20191028171528_InitialCreate.Designer.cs} (92%) rename src/Artemis.Storage/Migrations/{20191013153102_InitialCreate.cs => 20191028171528_InitialCreate.cs} (93%) diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 61acb02d0..251ed3094 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -148,13 +148,16 @@ + - - + + + + @@ -176,6 +179,7 @@ + @@ -186,6 +190,7 @@ + diff --git a/src/Artemis.Core/Events/DeviceConfigurationEventArgs.cs b/src/Artemis.Core/Events/DeviceConfigurationEventArgs.cs index 327647ef7..a2fd7d2ca 100644 --- a/src/Artemis.Core/Events/DeviceConfigurationEventArgs.cs +++ b/src/Artemis.Core/Events/DeviceConfigurationEventArgs.cs @@ -5,11 +5,11 @@ namespace Artemis.Core.Events { public class SurfaceConfigurationEventArgs : EventArgs { - public SurfaceConfigurationEventArgs(SurfaceConfiguration surfaceConfiguration) + public SurfaceConfigurationEventArgs(Surface surface) { - SurfaceConfiguration = surfaceConfiguration; + Surface = surface; } - public SurfaceConfiguration SurfaceConfiguration { get; } + public Surface Surface { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Extensions/RgbDeviceExtensions.cs b/src/Artemis.Core/Extensions/RgbDeviceExtensions.cs new file mode 100644 index 000000000..8e8a37c38 --- /dev/null +++ b/src/Artemis.Core/Extensions/RgbDeviceExtensions.cs @@ -0,0 +1,20 @@ +using RGB.NET.Core; + +namespace Artemis.Core.Extensions +{ + public static class RgbDeviceExtensions + { + public static int GetDeviceHashCode(this IRGBDevice rgbDevice) + { + unchecked + { + var hashCode = rgbDevice.DeviceInfo.DeviceName?.GetHashCode() ?? 0; + hashCode = (hashCode * 397) ^ (rgbDevice.DeviceInfo.Manufacturer?.GetHashCode() ?? 0); + hashCode = (hashCode * 397) ^ (rgbDevice.DeviceInfo.Model?.GetHashCode() ?? 0); + hashCode = (hashCode * 397) ^ (int) rgbDevice.DeviceInfo.DeviceType; + hashCode = (hashCode * 397) ^ (int) rgbDevice.DeviceInfo.Lighting; + return hashCode; + } + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs index 8d2556d04..121924fe7 100644 --- a/src/Artemis.Core/Models/Profile/Folder.cs +++ b/src/Artemis.Core/Models/Profile/Folder.cs @@ -27,7 +27,7 @@ namespace Artemis.Core.Models.Profile profileElement.Update(deltaTime); } - public void Render(double deltaTime, RGBSurface surface, Graphics graphics) + public void Render(double deltaTime, Surface.Surface surface, Graphics graphics) { // Folders don't render but their children do foreach (var profileElement in Children) diff --git a/src/Artemis.Core/Models/Profile/Interfaces/IProfileElement.cs b/src/Artemis.Core/Models/Profile/Interfaces/IProfileElement.cs index 95423f681..2cc72c88b 100644 --- a/src/Artemis.Core/Models/Profile/Interfaces/IProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/Interfaces/IProfileElement.cs @@ -30,6 +30,6 @@ namespace Artemis.Core.Models.Profile.Interfaces /// /// Renders the element /// - void Render(double deltaTime, RGBSurface surface, Graphics graphics); + void Render(double deltaTime, Surface.Surface surface, Graphics graphics); } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index bb3def768..1724b9ca0 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -6,7 +6,6 @@ using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Interfaces; using Artemis.Core.Services.Interfaces; using Artemis.Storage.Entities; -using RGB.NET.Core; namespace Artemis.Core.Models.Profile { @@ -36,7 +35,7 @@ namespace Artemis.Core.Models.Profile } } - public void Render(double deltaTime, RGBSurface surface, Graphics graphics) + public void Render(double deltaTime, Surface.Surface surface, Graphics graphics) { if (LayerType == null) return; diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index 228e44b40..9f9bdfae5 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -35,7 +35,7 @@ namespace Artemis.Core.Models.Profile } } - public void Render(double deltaTime, RGBSurface surface, Graphics graphics) + public void Render(double deltaTime, Surface.Surface surface, Graphics graphics) { lock (this) { diff --git a/src/Artemis.Core/Models/Surface/Device.cs b/src/Artemis.Core/Models/Surface/Device.cs new file mode 100644 index 000000000..161bea746 --- /dev/null +++ b/src/Artemis.Core/Models/Surface/Device.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.ObjectModel; +using System.Linq; +using Artemis.Core.Extensions; +using Artemis.Storage.Entities; +using RGB.NET.Core; +using Rectangle = System.Drawing.Rectangle; + +namespace Artemis.Core.Models.Surface +{ + public class Device + { + internal Device(IRGBDevice rgbDevice, Surface surface) + { + RgbDevice = rgbDevice; + Surface = surface; + Configuration = new DeviceEntity(); + Leds = rgbDevice.Select(l => new DeviceLed(l, this)).ToList().AsReadOnly(); + + Rotation = 0; + ZIndex = 1; + + ApplyToConfiguration(); + CalculateRenderRectangle(); + } + + internal Device(IRGBDevice rgbDevice, Surface surface, DeviceEntity configuration) + { + RgbDevice = rgbDevice; + Surface = surface; + Configuration = configuration; + Leds = rgbDevice.Select(l => new DeviceLed(l, this)).ToList().AsReadOnly(); + + Rotation = configuration.Rotation; + ZIndex = configuration.ZIndex; + } + + public Rectangle RenderRectangle { get; private set; } + + public IRGBDevice RgbDevice { get; private set; } + public Surface Surface { get; private set; } + public DeviceEntity Configuration { get; private set; } + public ReadOnlyCollection Leds { get; set; } + + public double X + { + get => Configuration.X; + set => Configuration.X = value; + } + + public double Y + { + get => Configuration.Y; + set => Configuration.Y = value; + } + + public double Rotation + { + get => Configuration.Rotation; + set => Configuration.Rotation = value; + } + + public int ZIndex + { + get => Configuration.ZIndex; + set => Configuration.ZIndex = value; + } + + internal void ApplyToConfiguration() + { + Configuration.SurfaceId = Surface.Guid; + Configuration.DeviceHashCode = RgbDevice.GetDeviceHashCode(); + + // Ensure the position configuration is in the surface configuration's' collection of positions + if (Surface.SurfaceEntity.DeviceEntities.All(p => p.Guid != Configuration.Guid)) + Surface.SurfaceEntity.DeviceEntities.Add(Configuration); + } + + internal void ApplyToRgbDevice() + { + RgbDevice.Location = new Point(Configuration.X, Configuration.Y); + CalculateRenderRectangle(); + } + + internal void CalculateRenderRectangle() + { + RenderRectangle = new Rectangle( + (int) Math.Round(RgbDevice.Location.X * Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbDevice.Location.Y * Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbDevice.Size.Width * Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbDevice.Size.Height * Surface.Scale, MidpointRounding.AwayFromZero) + ); + + foreach (var led in Leds) + led.CalculateRenderRectangle(); + } + + internal void Destroy() + { + Configuration = null; + RgbDevice = null; + Surface = null; + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Surface/Led.cs b/src/Artemis.Core/Models/Surface/Led.cs new file mode 100644 index 000000000..d34022fd9 --- /dev/null +++ b/src/Artemis.Core/Models/Surface/Led.cs @@ -0,0 +1,38 @@ +using System; +using RGB.NET.Core; +using Rectangle = System.Drawing.Rectangle; + +namespace Artemis.Core.Models.Surface +{ + public class DeviceLed + { + public DeviceLed(Led led, Device device) + { + RgbLed = led; + Device = device; + CalculateRenderRectangle(); + } + + public Led RgbLed { get; } + public Device Device { get; } + + public Rectangle RenderRectangle { get; private set; } + public Rectangle AbsoluteRenderRectangle { get; private set; } + + public void CalculateRenderRectangle() + { + RenderRectangle = new Rectangle( + (int) Math.Round(RgbLed.LedRectangle.X * Device.Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbLed.LedRectangle.Y * Device.Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbLed.LedRectangle.Width * Device.Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbLed.LedRectangle.Height * Device.Surface.Scale, MidpointRounding.AwayFromZero) + ); + AbsoluteRenderRectangle = new Rectangle( + (int) Math.Round(RgbLed.AbsoluteLedRectangle.X * Device.Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbLed.AbsoluteLedRectangle.Y * Device.Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbLed.AbsoluteLedRectangle.Width * Device.Surface.Scale, MidpointRounding.AwayFromZero), + (int) Math.Round(RgbLed.AbsoluteLedRectangle.Height * Device.Surface.Scale, MidpointRounding.AwayFromZero) + ); + } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Surface/Surface.cs b/src/Artemis.Core/Models/Surface/Surface.cs new file mode 100644 index 000000000..05fec03e7 --- /dev/null +++ b/src/Artemis.Core/Models/Surface/Surface.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.Extensions; +using Artemis.Storage.Entities; +using RGB.NET.Core; + +namespace Artemis.Core.Models.Surface +{ + public class Surface + { + internal Surface(RGBSurface rgbSurface, string name, double scale) + { + SurfaceEntity = new SurfaceEntity {DeviceEntities = new List()}; + Guid = System.Guid.NewGuid().ToString(); + + Name = name; + Scale = scale; + RgbSurface = rgbSurface; + IsActive = false; + Devices = new List(); + + ApplyToEntity(); + } + + internal Surface(RGBSurface rgbSurface, SurfaceEntity surfaceEntity, double scale) + { + RgbSurface = rgbSurface; + SurfaceEntity = surfaceEntity; + Scale = scale; + Guid = surfaceEntity.Guid; + + Name = surfaceEntity.Name; + IsActive = surfaceEntity.IsActive; + Devices = new List(); + + if (surfaceEntity.DeviceEntities == null) + return; + + foreach (var position in surfaceEntity.DeviceEntities) + { + var device = rgbSurface.Devices.FirstOrDefault(d => d.GetDeviceHashCode() == position.DeviceHashCode); + if (device != null) + Devices.Add(new Device(device, this, position)); + } + } + + public RGBSurface RgbSurface { get; } + public double Scale { get; private set; } + public string Name { get; set; } + public bool IsActive { get; internal set; } + public List Devices { get; internal set; } + + internal SurfaceEntity SurfaceEntity { get; set; } + internal string Guid { get; set; } + + internal void ApplyToEntity() + { + SurfaceEntity.Guid = Guid; + SurfaceEntity.Name = Name; + SurfaceEntity.IsActive = IsActive; + } + + internal void Destroy() + { + SurfaceEntity = null; + + foreach (var deviceConfiguration in Devices) + deviceConfiguration.Destroy(); + Devices.Clear(); + } + + public void UpdateScale(double value) + { + Scale = value; + foreach (var device in Devices) + device.CalculateRenderRectangle(); + + OnScaleChanged(); + } + + #region Events + + public event EventHandler ScaleChanged; + + protected virtual void OnScaleChanged() + { + ScaleChanged?.Invoke(this, EventArgs.Empty); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Surface/SurfaceConfiguration.cs b/src/Artemis.Core/Models/Surface/SurfaceConfiguration.cs deleted file mode 100644 index 5bf1675d6..000000000 --- a/src/Artemis.Core/Models/Surface/SurfaceConfiguration.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Collections.Generic; -using Artemis.Storage.Entities; - -namespace Artemis.Core.Models.Surface -{ - public class SurfaceConfiguration - { - internal SurfaceConfiguration(string name) - { - SurfaceEntity = new SurfaceEntity {SurfacePositions = new List()}; - Guid = System.Guid.NewGuid().ToString(); - - Name = name; - IsActive = false; - DeviceConfigurations = new List(); - - ApplyToEntity(); - } - - internal SurfaceConfiguration(SurfaceEntity surfaceEntity) - { - SurfaceEntity = surfaceEntity; - Guid = surfaceEntity.Guid; - - Name = surfaceEntity.Name; - IsActive = surfaceEntity.IsActive; - DeviceConfigurations = new List(); - - if (surfaceEntity.SurfacePositions == null) - return; - foreach (var position in surfaceEntity.SurfacePositions) - DeviceConfigurations.Add(new SurfaceDeviceConfiguration(position, this)); - } - - internal SurfaceEntity SurfaceEntity { get; set; } - internal string Guid { get; set; } - - public string Name { get; set; } - public bool IsActive { get; internal set; } - public List DeviceConfigurations { get; internal set; } - - internal void ApplyToEntity() - { - SurfaceEntity.Guid = Guid; - SurfaceEntity.Name = Name; - SurfaceEntity.IsActive = IsActive; - } - - internal void Destroy() - { - SurfaceEntity = null; - - foreach (var deviceConfiguration in DeviceConfigurations) - deviceConfiguration.Destroy(); - DeviceConfigurations.Clear(); - } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Models/Surface/SurfaceDeviceConfiguration.cs b/src/Artemis.Core/Models/Surface/SurfaceDeviceConfiguration.cs deleted file mode 100644 index 7cc2eea85..000000000 --- a/src/Artemis.Core/Models/Surface/SurfaceDeviceConfiguration.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Linq; -using Artemis.Storage.Entities; -using RGB.NET.Core; - -namespace Artemis.Core.Models.Surface -{ - public class SurfaceDeviceConfiguration - { - internal SurfaceDeviceConfiguration(IRGBDevice device, int deviceId, SurfaceConfiguration surface) - { - PositionEntity = new SurfacePositionEntity(); - Guid = System.Guid.NewGuid().ToString(); - - Device = device; - DeviceId = deviceId; - DeviceName = device.DeviceInfo.DeviceName; - DeviceModel = device.DeviceInfo.Model; - DeviceManufacturer = device.DeviceInfo.Manufacturer; - - X = device.Location.X; - Y = device.Location.Y; - Rotation = 0; - ZIndex = 1; - - Surface = surface; - - ApplyToEntity(); - } - - internal SurfaceDeviceConfiguration(SurfacePositionEntity positionEntity, SurfaceConfiguration surfaceConfiguration) - { - PositionEntity = positionEntity; - Guid = positionEntity.Guid; - - DeviceId = positionEntity.DeviceId; - DeviceName = positionEntity.DeviceName; - DeviceModel = positionEntity.DeviceModel; - DeviceManufacturer = positionEntity.DeviceManufacturer; - - X = positionEntity.X; - Y = positionEntity.Y; - Rotation = positionEntity.Rotation; - ZIndex = positionEntity.ZIndex; - - Surface = surfaceConfiguration; - } - - internal SurfacePositionEntity PositionEntity { get; set; } - internal string Guid { get; } - - public IRGBDevice Device { get; internal set; } - public int DeviceId { get; } - public string DeviceName { get; } - public string DeviceModel { get; } - public string DeviceManufacturer { get; } - - public double X { get; set; } - public double Y { get; set; } - public double Rotation { get; set; } - public int ZIndex { get; set; } - - public SurfaceConfiguration Surface { get; private set; } - - /// - /// Applies the configuration to the device - /// - internal void ApplyToDevice() - { - if (Device != null) - { - Device.Location = new Point(X, Y); - } - } - - /// - /// Must be called when saving to the database - /// - internal void ApplyToEntity() - { - PositionEntity.Guid = Guid; - PositionEntity.SurfaceId = Surface.Guid; - - PositionEntity.DeviceId = DeviceId; - PositionEntity.DeviceName = DeviceName; - PositionEntity.DeviceModel = DeviceModel; - PositionEntity.DeviceManufacturer = DeviceManufacturer; - - PositionEntity.X = X; - PositionEntity.Y = Y; - PositionEntity.Rotation = Rotation; - PositionEntity.ZIndex = ZIndex; - - // Ensure the position entity is in the surface entity's' collection of positions - if (Surface.SurfaceEntity.SurfacePositions.All(p => p.Guid != Guid)) - Surface.SurfaceEntity.SurfacePositions.Add(PositionEntity); - } - - public void Destroy() - { - PositionEntity = null; - Device = null; - Surface = null; - } - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Ninject/CoreModule.cs b/src/Artemis.Core/Ninject/CoreModule.cs index 831450fc3..d45822f38 100644 --- a/src/Artemis.Core/Ninject/CoreModule.cs +++ b/src/Artemis.Core/Ninject/CoreModule.cs @@ -1,5 +1,6 @@ using Artemis.Core.Exceptions; using Artemis.Core.Plugins.Models; +using Artemis.Core.Services; using Artemis.Core.Services.Interfaces; using Artemis.Storage.Repositories.Interfaces; using Ninject.Extensions.Conventions; @@ -25,6 +26,16 @@ namespace Artemis.Core.Ninject .Configure(c => c.InSingletonScope()); }); + // Bind all protected services as singletons TODO: Protect 'em + Kernel.Bind(x => + { + x.FromThisAssembly() + .SelectAllClasses() + .InheritedFrom() + .BindAllInterfaces() + .Configure(c => c.InSingletonScope()); + }); + // Bind all repositories as singletons Kernel.Bind(x => { @@ -34,7 +45,7 @@ namespace Artemis.Core.Ninject .BindAllInterfaces() .Configure(c => c.InSingletonScope()); }); - + Kernel.Bind().ToProvider(); Kernel.Bind().ToProvider(); } diff --git a/src/Artemis.Core/Ninject/SettingsServiceProvider.cs b/src/Artemis.Core/Ninject/SettingsServiceProvider.cs new file mode 100644 index 000000000..f622e9bdc --- /dev/null +++ b/src/Artemis.Core/Ninject/SettingsServiceProvider.cs @@ -0,0 +1,30 @@ +using Artemis.Core.Plugins.Abstract; +using Artemis.Core.Plugins.Exceptions; +using Artemis.Core.Plugins.Models; +using Artemis.Core.Services; +using Ninject; +using Ninject.Activation; + +namespace Artemis.Core.Ninject +{ + public class SettingsServiceProvider : Provider + { + private readonly SettingsService _instance; + + public SettingsServiceProvider(IKernel kernel) + { + // This is not lazy, but the core is always going to be using this anyway + _instance = kernel.Get(); + } + + protected override ISettingsService CreateInstance(IContext context) + { + var parentRequest = context.Request.ParentRequest; + if (parentRequest == null || typeof(Plugin).IsAssignableFrom(parentRequest.Service)) + throw new ArtemisPluginException($"SettingsService can not be injected into a plugin. Inject {nameof(PluginSettings)} instead."); + + return _instance; + } + + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Abstract/LayerType.cs b/src/Artemis.Core/Plugins/Abstract/LayerType.cs index ac6717f70..676d43387 100644 --- a/src/Artemis.Core/Plugins/Abstract/LayerType.cs +++ b/src/Artemis.Core/Plugins/Abstract/LayerType.cs @@ -1,5 +1,6 @@ using System.Drawing; using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; using RGB.NET.Core; @@ -24,6 +25,6 @@ namespace Artemis.Core.Plugins.Abstract /// /// Renders the layer type /// - public abstract void Render(Layer device, RGBSurface surface, Graphics graphics); + public abstract void Render(Layer device, Surface surface, Graphics graphics); } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Abstract/Module.cs b/src/Artemis.Core/Plugins/Abstract/Module.cs index 2b0c592c2..5526dcea4 100644 --- a/src/Artemis.Core/Plugins/Abstract/Module.cs +++ b/src/Artemis.Core/Plugins/Abstract/Module.cs @@ -1,4 +1,5 @@ using System.Drawing; +using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; using RGB.NET.Core; using Stylet; @@ -38,7 +39,7 @@ namespace Artemis.Core.Plugins.Abstract /// Time since the last render /// The RGB Surface to render to /// - public abstract void Render(double deltaTime, RGBSurface surface, Graphics graphics); + public abstract void Render(double deltaTime, Surface surface, Graphics graphics); /// /// Called when the module's main view is being shown diff --git a/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs b/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs index a5561457b..31c1b6cd0 100644 --- a/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs +++ b/src/Artemis.Core/Plugins/Abstract/ProfileModule.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; using RGB.NET.Core; @@ -25,7 +26,7 @@ namespace Artemis.Core.Plugins.Abstract } /// - public override void Render(double deltaTime, RGBSurface surface, Graphics graphics) + public override void Render(double deltaTime, Surface surface, Graphics graphics) { lock (this) { diff --git a/src/Artemis.Core/Plugins/Models/PluginSetting.cs b/src/Artemis.Core/Plugins/Models/PluginSetting.cs index 876a3d1e7..219234956 100644 --- a/src/Artemis.Core/Plugins/Models/PluginSetting.cs +++ b/src/Artemis.Core/Plugins/Models/PluginSetting.cs @@ -1,11 +1,14 @@ -using System.Threading.Tasks; +using System; +using System.ComponentModel; +using System.Threading.Tasks; using Artemis.Storage.Entities; using Artemis.Storage.Repositories.Interfaces; using Newtonsoft.Json; +using Stylet; namespace Artemis.Core.Plugins.Models { - public class PluginSetting + public class PluginSetting : PropertyChangedBase { // ReSharper disable once NotAccessedField.Local private readonly PluginInfo _pluginInfo; @@ -20,6 +23,15 @@ namespace Artemis.Core.Plugins.Models Name = pluginSettingEntity.Name; Value = JsonConvert.DeserializeObject(pluginSettingEntity.Value); + + // PropertyChanged is for bindings, but we can use it here to create a easy to use SettingsChanged event + PropertyChanged += OnPropertyChanged; + } + + private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Value)) + OnSettingChanged(); } /// @@ -69,5 +81,12 @@ namespace Artemis.Core.Plugins.Models _pluginSettingEntity.Value = JsonConvert.SerializeObject(Value); await _pluginSettingRepository.SaveAsync(); } + + public event EventHandler SettingChanged; + + protected virtual void OnSettingChanged() + { + SettingChanged?.Invoke(this, EventArgs.Empty); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Models/PluginSettings.cs b/src/Artemis.Core/Plugins/Models/PluginSettings.cs index f4c32d04d..dd1c1b967 100644 --- a/src/Artemis.Core/Plugins/Models/PluginSettings.cs +++ b/src/Artemis.Core/Plugins/Models/PluginSettings.cs @@ -6,6 +6,10 @@ using Newtonsoft.Json; namespace Artemis.Core.Plugins.Models { + /// + /// This contains all the settings for your plugin. To access a setting use . + /// To use this class, inject it into the constructor of your plugin. + /// public class PluginSettings { private readonly PluginInfo _pluginInfo; @@ -19,17 +23,27 @@ namespace Artemis.Core.Plugins.Models _settingEntities = pluginSettingRepository.GetByPluginGuid(_pluginInfo.Guid).ToDictionary(se => se.Name); } + /// + /// Gets the setting with the provided name. If the setting does not exist yet, it is created. + /// + /// The type of the setting, can be any serializable type + /// The name of the setting + /// The default value to use if the setting does not exist yet + /// public PluginSetting GetSetting(string name, T defaultValue = default(T)) { - if (_settingEntities.ContainsKey(name)) + lock (_settingEntities) + { + if (_settingEntities.ContainsKey(name)) + return new PluginSetting(_pluginInfo, _pluginSettingRepository, _settingEntities[name]); + + var settingEntity = new PluginSettingEntity {Name = name, PluginGuid = _pluginInfo.Guid, Value = JsonConvert.SerializeObject(defaultValue)}; + _pluginSettingRepository.Add(settingEntity); + _pluginSettingRepository.Save(); + + _settingEntities.Add(name, settingEntity); return new PluginSetting(_pluginInfo, _pluginSettingRepository, _settingEntities[name]); - - var settingEntity = new PluginSettingEntity {Name = name, PluginGuid = _pluginInfo.Guid, Value = JsonConvert.SerializeObject(defaultValue)}; - _pluginSettingRepository.Add(settingEntity); - _pluginSettingRepository.Save(); - - _settingEntities.Add(name, settingEntity); - return new PluginSetting(_pluginInfo, _pluginSettingRepository, _settingEntities[name]); + } } } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index 7be6e9fe2..37e8b13bb 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -52,11 +52,11 @@ namespace Artemis.Core.Services await Task.Run(() => _pluginService.CopyBuiltInPlugins()); await Task.Run(() => _pluginService.LoadPlugins()); - var surfaceConfig = _surfaceService.ActiveSurfaceConfiguration; + var surfaceConfig = _surfaceService.ActiveSurface; if (surfaceConfig != null) - _logger.Information("Initialized with active surface configuration {surfaceConfig}-{guid}", surfaceConfig.Name, surfaceConfig.Guid); + _logger.Information("Initialized with active surface entity {surfaceConfig}-{guid}", surfaceConfig.Name, surfaceConfig.Guid); else - _logger.Information("Initialized without an active surface configuration"); + _logger.Information("Initialized without an active surface entity"); OnInitialized(); } @@ -84,7 +84,7 @@ namespace Artemis.Core.Services g.Clear(Color.Black); foreach (var module in modules) - module.Render(args.DeltaTime, _rgbService.Surface, g); + module.Render(args.DeltaTime, _surfaceService.ActiveSurface, g); } OnFrameRendered(new FrameEventArgs(modules, _rgbService.GraphicsDecorator.GetBitmap(), args.DeltaTime, _rgbService.Surface)); diff --git a/src/Artemis.Core/Services/Interfaces/IArtemisService.cs b/src/Artemis.Core/Services/Interfaces/IArtemisService.cs index 2340610a1..f002df680 100644 --- a/src/Artemis.Core/Services/Interfaces/IArtemisService.cs +++ b/src/Artemis.Core/Services/Interfaces/IArtemisService.cs @@ -1,5 +1,8 @@ namespace Artemis.Core.Services.Interfaces { + /// + /// A singleton service + /// public interface IArtemisService { } diff --git a/src/Artemis.Core/Services/Interfaces/IProtectedArtemisService.cs b/src/Artemis.Core/Services/Interfaces/IProtectedArtemisService.cs new file mode 100644 index 000000000..2f1828d92 --- /dev/null +++ b/src/Artemis.Core/Services/Interfaces/IProtectedArtemisService.cs @@ -0,0 +1,9 @@ +namespace Artemis.Core.Services.Interfaces +{ + /// + /// A singleton service that cannot be used by plugins + /// + public interface IProtectedArtemisService + { + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/PluginService.cs b/src/Artemis.Core/Services/PluginService.cs index df58cc4ae..d9a57bd59 100644 --- a/src/Artemis.Core/Services/PluginService.cs +++ b/src/Artemis.Core/Services/PluginService.cs @@ -102,7 +102,7 @@ namespace Artemis.Core.Services // Create a child kernel and app domain that will only contain the plugins _childKernel = new ChildKernel(_kernel); - + // Load the plugin assemblies into the plugin context var pluginDirectory = new DirectoryInfo(Path.Combine(Constants.DataFolder, "plugins")); foreach (var subDirectory in pluginDirectory.EnumerateDirectories()) diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs index 510c10394..47ee3d9e4 100644 --- a/src/Artemis.Core/Services/RgbService.cs +++ b/src/Artemis.Core/Services/RgbService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Artemis.Core.Events; +using Artemis.Core.Plugins.Models; using Artemis.Core.RGB.NET; using Artemis.Core.Services.Interfaces; using Artemis.Core.Services.Storage; @@ -20,15 +21,18 @@ namespace Artemis.Core.Services private readonly ILogger _logger; private readonly TimerUpdateTrigger _updateTrigger; private ListLedGroup _background; + private PluginSetting _renderScaleSetting; - internal RgbService(ILogger logger) + internal RgbService(ILogger logger, ISettingsService settingsService) { _logger = logger; + _renderScaleSetting = settingsService.GetSetting("RenderScale", 1.0); + Surface = RGBSurface.Instance; // Let's throw these for now Surface.Exception += SurfaceOnException; - + _renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged; _loadedDevices = new List(); _updateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / 25}; Surface.RegisterUpdateTrigger(_updateTrigger); @@ -39,16 +43,7 @@ namespace Artemis.Core.Services public GraphicsDecorator GraphicsDecorator { get; private set; } - public IReadOnlyCollection LoadedDevices - { - get - { - lock (_loadedDevices) - { - return _loadedDevices.AsReadOnly(); - } - } - } + public IReadOnlyCollection LoadedDevices => _loadedDevices.AsReadOnly(); public void AddDeviceProvider(IRGBDeviceProvider deviceProvider) { @@ -56,23 +51,20 @@ namespace Artemis.Core.Services if (deviceProvider.Devices == null) { - _logger.Warning("Device provider {deviceProvider} has no devices", deviceProvider.GetType().Name); + _logger.Warning("RgbDevice provider {deviceProvider} has no devices", deviceProvider.GetType().Name); return; } - lock (_loadedDevices) + foreach (var surfaceDevice in deviceProvider.Devices) { - foreach (var surfaceDevice in deviceProvider.Devices) + if (!_loadedDevices.Contains(surfaceDevice)) { - if (!_loadedDevices.Contains(surfaceDevice)) - { - _loadedDevices.Add(surfaceDevice); - OnDeviceLoaded(new DeviceEventArgs(surfaceDevice)); - } - else - { - OnDeviceReloaded(new DeviceEventArgs(surfaceDevice)); - } + _loadedDevices.Add(surfaceDevice); + OnDeviceLoaded(new DeviceEventArgs(surfaceDevice)); + } + else + { + OnDeviceReloaded(new DeviceEventArgs(surfaceDevice)); } } } @@ -85,6 +77,11 @@ namespace Artemis.Core.Services Surface.Dispose(); } + private void RenderScaleSettingOnSettingChanged(object sender, EventArgs e) + { + UpdateGraphicsDecorator(); + } + private void SurfaceOnException(ExceptionEventArgs args) { throw args.Exception; @@ -108,7 +105,7 @@ namespace Artemis.Core.Services // Apply the application wide brush and decorator _background = new ListLedGroup(Surface.Leds) {Brush = new SolidColorBrush(new Color(255, 255, 255, 255))}; - GraphicsDecorator = new GraphicsDecorator(_background, 0.25); + GraphicsDecorator = new GraphicsDecorator(_background, _renderScaleSetting.Value); _background.Brush.RemoveAllDecorators(); _background.Brush.AddDecorator(GraphicsDecorator); diff --git a/src/Artemis.Core/Services/SettingsService.cs b/src/Artemis.Core/Services/SettingsService.cs new file mode 100644 index 000000000..9c59763ef --- /dev/null +++ b/src/Artemis.Core/Services/SettingsService.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Artemis.Core.Plugins.Models; +using Artemis.Core.Services.Interfaces; +using Artemis.Storage.Entities; +using Artemis.Storage.Repositories.Interfaces; +using Newtonsoft.Json; + +namespace Artemis.Core.Services +{ + /// + public class SettingsService : ISettingsService + { + private readonly PluginInfo _buildInPluginInfo; + private readonly IPluginSettingRepository _pluginSettingRepository; + private readonly Dictionary _settingEntities; + + internal SettingsService(IPluginSettingRepository pluginSettingRepository) + { + _pluginSettingRepository = pluginSettingRepository; + _buildInPluginInfo = new PluginInfo {Guid = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"), Name = "Artemis Core"}; + + _settingEntities = pluginSettingRepository.GetByPluginGuid(_buildInPluginInfo.Guid).ToDictionary(se => se.Name); + } + + public PluginSetting GetSetting(string name, T defaultValue = default(T)) + { + lock (_settingEntities) + { + if (_settingEntities.ContainsKey(name)) + return new PluginSetting(_buildInPluginInfo, _pluginSettingRepository, _settingEntities[name]); + + var settingEntity = new PluginSettingEntity {Name = name, PluginGuid = _buildInPluginInfo.Guid, Value = JsonConvert.SerializeObject(defaultValue)}; + _pluginSettingRepository.Add(settingEntity); + _pluginSettingRepository.Save(); + + _settingEntities.Add(name, settingEntity); + return new PluginSetting(_buildInPluginInfo, _pluginSettingRepository, _settingEntities[name]); + } + } + } + + /// + /// A wrapper around plugin settings for internal use. + /// Do not inject into a plugin, for plugins inject instead. + /// + public interface ISettingsService : IProtectedArtemisService + { + PluginSetting GetSetting(string name, T defaultValue = default(T)); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/Storage/ISurfaceService.cs b/src/Artemis.Core/Services/Storage/ISurfaceService.cs index 5876b0dda..50cea7b92 100644 --- a/src/Artemis.Core/Services/Storage/ISurfaceService.cs +++ b/src/Artemis.Core/Services/Storage/ISurfaceService.cs @@ -9,43 +9,43 @@ namespace Artemis.Core.Services.Storage public interface ISurfaceService : IArtemisService { /// - /// Gets the currently active surface configuration, to change config use + /// Gets the currently active surface entity, to change config use /// - SurfaceConfiguration ActiveSurfaceConfiguration { get; } + Surface ActiveSurface { get; } /// /// Gets a read-only list of all surface configurations /// - ReadOnlyCollection SurfaceConfigurations { get; } + ReadOnlyCollection SurfaceConfigurations { get; } /// - /// Creates a new surface configuration with the supplied name + /// Creates a new surface entity with the supplied name /// - /// The name for the new surface configuration + /// The name for the new surface entity /// - SurfaceConfiguration CreateSurfaceConfiguration(string name); + Surface CreateSurfaceConfiguration(string name); /// - /// Sets the provided configuration as active and applies it to the surface + /// Sets the provided entity as active and applies it to the surface /// - /// The configuration to activate and apply - void SetActiveSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration); + /// The entity to activate and apply + void SetActiveSurfaceConfiguration(Surface surface); /// - /// Saves the provided surface configuration to permanent storage and if config is active, applies it to the surface + /// Saves the provided surface entity to permanent storage and if config is active, applies it to the surface /// - /// The configuration to save (and apply if active) + /// The entity to save (and apply if active) /// Whether to also save devices. If false, devices changes won't be applied either - void UpdateSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration, bool includeDevices); + void UpdateSurfaceConfiguration(Surface surface, bool includeDevices); /// - /// Deletes the supplied surface configuration, surface configuration may not be the active surface configuration + /// Deletes the supplied surface entity, surface entity may not be the active surface entity /// - /// The surface configuration to delete, may not be the active surface configuration - void DeleteSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration); + /// The surface entity to delete, may not be the active surface entity + void DeleteSurfaceConfiguration(Surface surface); /// - /// Occurs when the active device configuration has been changed + /// Occurs when the active device entity has been changed /// event EventHandler ActiveSurfaceConfigurationChanged; } diff --git a/src/Artemis.Core/Services/Storage/SurfaceService.cs b/src/Artemis.Core/Services/Storage/SurfaceService.cs index 42ca397df..c0492d8cd 100644 --- a/src/Artemis.Core/Services/Storage/SurfaceService.cs +++ b/src/Artemis.Core/Services/Storage/SurfaceService.cs @@ -4,7 +4,9 @@ using System.Collections.ObjectModel; using System.Linq; using Artemis.Core.Events; using Artemis.Core.Exceptions; +using Artemis.Core.Extensions; using Artemis.Core.Models.Surface; +using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Interfaces; using Artemis.Storage.Repositories.Interfaces; using RGB.NET.Core; @@ -16,45 +18,37 @@ namespace Artemis.Core.Services.Storage { private readonly ILogger _logger; private readonly IRgbService _rgbService; - private readonly List _surfaceConfigurations; + private readonly List _surfaceConfigurations; private readonly ISurfaceRepository _surfaceRepository; + private readonly PluginSetting _renderScaleSetting; - public SurfaceService(ILogger logger, ISurfaceRepository surfaceRepository, IRgbService rgbService) + internal SurfaceService(ILogger logger, ISurfaceRepository surfaceRepository, IRgbService rgbService, ISettingsService settingsService) { _logger = logger; _surfaceRepository = surfaceRepository; _rgbService = rgbService; - _surfaceConfigurations = new List(); + _surfaceConfigurations = new List(); + _renderScaleSetting = settingsService.GetSetting("RenderScale", 1.0); LoadFromRepository(); _rgbService.DeviceLoaded += RgbServiceOnDeviceLoaded; + _renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged; } - public SurfaceConfiguration ActiveSurfaceConfiguration { get; private set; } - public ReadOnlyCollection SurfaceConfigurations - { - get - { - lock (_surfaceConfigurations) - { - return _surfaceConfigurations.AsReadOnly(); - } - } - } - public SurfaceConfiguration CreateSurfaceConfiguration(string name) + public Surface ActiveSurface { get; private set; } + public ReadOnlyCollection SurfaceConfigurations => _surfaceConfigurations.AsReadOnly(); + + public Surface CreateSurfaceConfiguration(string name) { // Create a blank config - var configuration = new SurfaceConfiguration(name); + var configuration = new Surface(_rgbService.Surface, name, _renderScaleSetting.Value); // Add all current devices - foreach (var rgbDevice in _rgbService.LoadedDevices) - { - var deviceId = GetDeviceId(rgbDevice); - configuration.DeviceConfigurations.Add(new SurfaceDeviceConfiguration(rgbDevice, deviceId, configuration)); - } + foreach (var rgbDevice in _rgbService.LoadedDevices) + configuration.Devices.Add(new Device(rgbDevice, configuration)); lock (_surfaceConfigurations) { @@ -64,67 +58,67 @@ namespace Artemis.Core.Services.Storage } } - public void SetActiveSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration) + public void SetActiveSurfaceConfiguration(Surface surface) { - if (ActiveSurfaceConfiguration == surfaceConfiguration) + if (ActiveSurface == surface) return; - // Set the new configuration - ActiveSurfaceConfiguration = surfaceConfiguration; + // Set the new entity + ActiveSurface = surface; - // Ensure only the new configuration is marked as active + // Ensure only the new entity is marked as active lock (_surfaceConfigurations) { - // Mark only the new surfaceConfiguration as active + // Mark only the new surface as active foreach (var configuration in _surfaceConfigurations) { - configuration.IsActive = configuration == ActiveSurfaceConfiguration; + configuration.IsActive = configuration == ActiveSurface; configuration.ApplyToEntity(); } _surfaceRepository.Save(); } - // Apply the active surface configuration to the devices - if (ActiveSurfaceConfiguration != null) + // Apply the active surface entity to the devices + if (ActiveSurface != null) { - foreach (var deviceConfiguration in ActiveSurfaceConfiguration.DeviceConfigurations) - deviceConfiguration.ApplyToDevice(); + foreach (var device in ActiveSurface.Devices) + device.ApplyToRgbDevice(); } - // Update the RGB service's graphics decorator to work with the new surface configuration + // Update the RGB service's graphics decorator to work with the new surface entity _rgbService.UpdateGraphicsDecorator(); - OnActiveSurfaceConfigurationChanged(new SurfaceConfigurationEventArgs(ActiveSurfaceConfiguration)); + OnActiveSurfaceConfigurationChanged(new SurfaceConfigurationEventArgs(ActiveSurface)); } - public void UpdateSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration, bool includeDevices) + public void UpdateSurfaceConfiguration(Surface surface, bool includeDevices) { - surfaceConfiguration.ApplyToEntity(); + surface.ApplyToEntity(); if (includeDevices) { - foreach (var deviceConfiguration in surfaceConfiguration.DeviceConfigurations) + foreach (var deviceConfiguration in surface.Devices) { - deviceConfiguration.ApplyToEntity(); - if (surfaceConfiguration.IsActive) - deviceConfiguration.ApplyToDevice(); + deviceConfiguration.ApplyToConfiguration(); + if (surface.IsActive) + deviceConfiguration.ApplyToRgbDevice(); } } _surfaceRepository.Save(); _rgbService.UpdateGraphicsDecorator(); - OnSurfaceConfigurationUpdated(new SurfaceConfigurationEventArgs(surfaceConfiguration)); + OnSurfaceConfigurationUpdated(new SurfaceConfigurationEventArgs(surface)); } - public void DeleteSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration) + public void DeleteSurfaceConfiguration(Surface surface) { - if (surfaceConfiguration == ActiveSurfaceConfiguration) - throw new ArtemisCoreException($"Cannot delete surface configuration '{surfaceConfiguration.Name}' because it is active."); + if (surface == ActiveSurface) + throw new ArtemisCoreException($"Cannot delete surface entity '{surface.Name}' because it is active."); lock (_surfaceConfigurations) { - var entity = surfaceConfiguration.SurfaceEntity; - surfaceConfiguration.Destroy(); - _surfaceConfigurations.Remove(surfaceConfiguration); + var entity = surface.SurfaceEntity; + surface.Destroy(); + _surfaceConfigurations.Remove(surface); _surfaceRepository.Remove(entity); _surfaceRepository.Save(); @@ -138,10 +132,17 @@ namespace Artemis.Core.Services.Storage lock (_surfaceConfigurations) { foreach (var surfaceConfiguration in _surfaceConfigurations) - MatchDeviceConfiguration(e.Device, surfaceConfiguration); + AddDeviceIfMissing(e.Device, surfaceConfiguration); } - UpdateSurfaceConfiguration(ActiveSurfaceConfiguration, true); + UpdateSurfaceConfiguration(ActiveSurface, true); + } + + private void RenderScaleSettingOnSettingChanged(object sender, EventArgs e) + { + foreach (var surfaceConfiguration in SurfaceConfigurations) + surfaceConfiguration.UpdateScale(_renderScaleSetting.Value); + } #endregion @@ -153,12 +154,9 @@ namespace Artemis.Core.Services.Storage var configs = _surfaceRepository.GetAll(); foreach (var surfaceEntity in configs) { - // Create the surface configuration - var surfaceConfiguration = new SurfaceConfiguration(surfaceEntity); - // For each loaded device, match a device configuration - var devices = _rgbService.LoadedDevices; - foreach (var rgbDevice in devices) - MatchDeviceConfiguration(rgbDevice, surfaceConfiguration); + // Create the surface entity + var surfaceConfiguration = new Surface(_rgbService.Surface, surfaceEntity, _renderScaleSetting.Value); + // Finally, add the surface config to the collection lock (_surfaceConfigurations) { @@ -170,39 +168,44 @@ namespace Artemis.Core.Services.Storage var active = SurfaceConfigurations.FirstOrDefault(c => c.IsActive); if (active != null) SetActiveSurfaceConfiguration(active); + else + { + active = SurfaceConfigurations.FirstOrDefault(); + if (active != null) + SetActiveSurfaceConfiguration(active); + else + SetActiveSurfaceConfiguration(CreateSurfaceConfiguration("Default")); + } } #endregion #region Utilities - private void MatchDeviceConfiguration(IRGBDevice rgbDevice, SurfaceConfiguration surfaceConfiguration) + private void AddDeviceIfMissing(IRGBDevice rgbDevice, Surface surface) { - var deviceId = GetDeviceId(rgbDevice); - var deviceConfig = surfaceConfiguration.DeviceConfigurations.FirstOrDefault(d => d.DeviceName == rgbDevice.DeviceInfo.DeviceName && - d.DeviceModel == rgbDevice.DeviceInfo.Model && - d.DeviceManufacturer == rgbDevice.DeviceInfo.Manufacturer && - d.DeviceId == deviceId); + var deviceHashCode = rgbDevice.GetDeviceHashCode(); + var device = surface.Devices.FirstOrDefault(d => d.Configuration.DeviceHashCode == deviceHashCode); - if (deviceConfig == null) + if (device != null) + return; + + // Find an existing device config and use that + var existingDeviceConfig = surface.SurfaceEntity.DeviceEntities.FirstOrDefault(d => d.DeviceHashCode == deviceHashCode); + if (existingDeviceConfig != null) + device = new Device(rgbDevice,surface, existingDeviceConfig); + // Fall back on creating a new device + else { - _logger.Information("No active surface config found for {deviceInfo}, device ID: {deviceId}. Adding a new entry.", rgbDevice.DeviceInfo, deviceId); - deviceConfig = new SurfaceDeviceConfiguration(rgbDevice, deviceId, surfaceConfiguration); - surfaceConfiguration.DeviceConfigurations.Add(deviceConfig); + _logger.Information( + "No device config found for {deviceInfo}, device hash: {deviceHashCode}. Adding a new entry.", + rgbDevice.DeviceInfo, + deviceHashCode + ); + device = new Device(rgbDevice, surface); } - deviceConfig.Device = rgbDevice; - deviceConfig.ApplyToDevice(); - } - - private int GetDeviceId(IRGBDevice rgbDevice) - { - return _rgbService.LoadedDevices - .Where(d => d.DeviceInfo.DeviceName == rgbDevice.DeviceInfo.DeviceName && - d.DeviceInfo.Model == rgbDevice.DeviceInfo.Model && - d.DeviceInfo.Manufacturer == rgbDevice.DeviceInfo.Manufacturer) - .ToList() - .IndexOf(rgbDevice) + 1; + surface.Devices.Add(device); } #endregion diff --git a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerType.cs b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerType.cs index ff3707bae..9b4d5d4dd 100644 --- a/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerType.cs +++ b/src/Artemis.Plugins.LayerTypes.Brush/BrushLayerType.cs @@ -1,5 +1,6 @@ using System.Drawing; using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Models; using QRCoder; @@ -31,7 +32,7 @@ namespace Artemis.Plugins.LayerTypes.Brush // Update the brush } - public override void Render(Layer device, RGBSurface surface, Graphics graphics) + public override void Render(Layer device, Surface surface, Graphics graphics) { } diff --git a/src/Artemis.Plugins.Modules.General/GeneralModule.cs b/src/Artemis.Plugins.Modules.General/GeneralModule.cs index 92c373c4a..6acb89269 100644 --- a/src/Artemis.Plugins.Modules.General/GeneralModule.cs +++ b/src/Artemis.Plugins.Modules.General/GeneralModule.cs @@ -1,13 +1,12 @@ using System; using System.Drawing; -using Artemis.Core.Extensions; +using System.Linq; +using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.Models; +using Artemis.Core.Services; using Artemis.Plugins.Modules.General.ViewModels; -using RGB.NET.Core; using Stylet; -using Color = System.Drawing.Color; -using Rectangle = System.Drawing.Rectangle; namespace Artemis.Plugins.Modules.General { @@ -15,7 +14,7 @@ namespace Artemis.Plugins.Modules.General { private readonly PluginSettings _settings; - public GeneralModule(PluginInfo pluginInfo, PluginSettings settings) : base(pluginInfo) + public GeneralModule(PluginInfo pluginInfo, PluginSettings settings, ISettingsService settingsService) : base(pluginInfo) { _settings = settings; DisplayName = "General"; @@ -44,7 +43,7 @@ namespace Artemis.Plugins.Modules.General } } - public override void Render(double deltaTime, RGBSurface surface, Graphics graphics) + public override void Render(double deltaTime, Surface surface, Graphics graphics) { // Per-device coloring, slower // RenderPerDevice(surface, graphics); @@ -53,11 +52,11 @@ namespace Artemis.Plugins.Modules.General RenderPerLed(surface, graphics); } - public void RenderFullSurface(RGBSurface surface, Graphics graphics) + public void RenderFullSurface(Surface surface, Graphics graphics) { } - public void RenderPerDevice(RGBSurface surface, Graphics graphics) + public void RenderPerDevice(Surface surface, Graphics graphics) { var index = 0; foreach (var device in surface.Devices) @@ -69,16 +68,15 @@ namespace Artemis.Plugins.Modules.General Colors[index] = color; } - var rectangle = new Rectangle((int) device.Location.X, (int) device.Location.Y, (int) device.Size.Width, (int) device.Size.Height); - graphics.FillRectangle(new SolidBrush(color), rectangle); + graphics.FillRectangle(new SolidBrush(color), device.RenderRectangle); index++; } } - public void RenderPerLed(RGBSurface surface, Graphics graphics) + public void RenderPerLed(Surface surface, Graphics graphics) { var index = 0; - foreach (var led in surface.Leds) + foreach (var led in surface.Devices.SelectMany(d => d.Leds)) { var color = Colors[index]; if (color.A == 0) @@ -87,8 +85,7 @@ namespace Artemis.Plugins.Modules.General Colors[index] = color; } - var rectangle = led.AbsoluteLedRectangle.ToDrawingRectangle(0.25); - graphics.FillRectangle(new SolidBrush(color), rectangle); + graphics.FillRectangle(new SolidBrush(color), led.AbsoluteRenderRectangle); index++; } } diff --git a/src/Artemis.Storage/Entities/SurfacePositionEntity.cs b/src/Artemis.Storage/Entities/DeviceEntity.cs similarity index 64% rename from src/Artemis.Storage/Entities/SurfacePositionEntity.cs rename to src/Artemis.Storage/Entities/DeviceEntity.cs index 5c115c363..e6df74a4d 100644 --- a/src/Artemis.Storage/Entities/SurfacePositionEntity.cs +++ b/src/Artemis.Storage/Entities/DeviceEntity.cs @@ -2,16 +2,17 @@ namespace Artemis.Storage.Entities { - public class SurfacePositionEntity + public class DeviceEntity { + public DeviceEntity() + { + Guid = System.Guid.NewGuid().ToString(); + } + [Key] public string Guid { get; set; } - public int DeviceId { get; set; } - public string DeviceName { get; set; } - public string DeviceModel { get; set; } - public string DeviceManufacturer { get; set; } - + public int DeviceHashCode { get; set; } public double X { get; set; } public double Y { get; set; } public double Rotation { get; set; } diff --git a/src/Artemis.Storage/Entities/SurfaceEntity.cs b/src/Artemis.Storage/Entities/SurfaceEntity.cs index 1f5ee520d..3afb05b0d 100644 --- a/src/Artemis.Storage/Entities/SurfaceEntity.cs +++ b/src/Artemis.Storage/Entities/SurfaceEntity.cs @@ -5,12 +5,17 @@ namespace Artemis.Storage.Entities { public class SurfaceEntity { + public SurfaceEntity() + { + Guid = System.Guid.NewGuid().ToString(); + } + [Key] public string Guid { get; set; } public string Name { get; set; } public bool IsActive { get; set; } - public virtual ICollection SurfacePositions { get; set; } + public virtual ICollection DeviceEntities { get; set; } } } \ No newline at end of file diff --git a/src/Artemis.Storage/Migrations/20191013153102_InitialCreate.Designer.cs b/src/Artemis.Storage/Migrations/20191028171528_InitialCreate.Designer.cs similarity index 92% rename from src/Artemis.Storage/Migrations/20191013153102_InitialCreate.Designer.cs rename to src/Artemis.Storage/Migrations/20191028171528_InitialCreate.Designer.cs index e168cd87d..3e71f340f 100644 --- a/src/Artemis.Storage/Migrations/20191013153102_InitialCreate.Designer.cs +++ b/src/Artemis.Storage/Migrations/20191028171528_InitialCreate.Designer.cs @@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Artemis.Storage.Migrations { [DbContext(typeof(StorageContext))] - [Migration("20191013153102_InitialCreate")] + [Migration("20191028171528_InitialCreate")] partial class InitialCreate { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -18,6 +18,30 @@ namespace Artemis.Storage.Migrations modelBuilder .HasAnnotation("ProductVersion", "2.2.4-servicing-10062"); + modelBuilder.Entity("Artemis.Storage.Entities.DeviceEntity", b => + { + b.Property("Guid") + .ValueGeneratedOnAdd(); + + b.Property("DeviceHashCode"); + + b.Property("Rotation"); + + b.Property("SurfaceId"); + + b.Property("X"); + + b.Property("Y"); + + b.Property("ZIndex"); + + b.HasKey("Guid"); + + b.HasIndex("SurfaceId"); + + b.ToTable("DeviceEntity"); + }); + modelBuilder.Entity("Artemis.Storage.Entities.FolderEntity", b => { b.Property("Guid") @@ -167,34 +191,11 @@ namespace Artemis.Storage.Migrations b.ToTable("Surfaces"); }); - modelBuilder.Entity("Artemis.Storage.Entities.SurfacePositionEntity", b => + modelBuilder.Entity("Artemis.Storage.Entities.DeviceEntity", b => { - b.Property("Guid") - .ValueGeneratedOnAdd(); - - b.Property("DeviceId"); - - b.Property("DeviceManufacturer"); - - b.Property("DeviceModel"); - - b.Property("DeviceName"); - - b.Property("Rotation"); - - b.Property("SurfaceId"); - - b.Property("X"); - - b.Property("Y"); - - b.Property("ZIndex"); - - b.HasKey("Guid"); - - b.HasIndex("SurfaceId"); - - b.ToTable("SurfacePositionEntity"); + b.HasOne("Artemis.Storage.Entities.SurfaceEntity", "Surface") + .WithMany("DeviceEntities") + .HasForeignKey("SurfaceId"); }); modelBuilder.Entity("Artemis.Storage.Entities.FolderEntity", b => @@ -238,13 +239,6 @@ namespace Artemis.Storage.Migrations .WithMany() .HasForeignKey("RootFolderGuid"); }); - - modelBuilder.Entity("Artemis.Storage.Entities.SurfacePositionEntity", b => - { - b.HasOne("Artemis.Storage.Entities.SurfaceEntity", "Surface") - .WithMany("SurfacePositions") - .HasForeignKey("SurfaceId"); - }); #pragma warning restore 612, 618 } } diff --git a/src/Artemis.Storage/Migrations/20191013153102_InitialCreate.cs b/src/Artemis.Storage/Migrations/20191028171528_InitialCreate.cs similarity index 93% rename from src/Artemis.Storage/Migrations/20191013153102_InitialCreate.cs rename to src/Artemis.Storage/Migrations/20191028171528_InitialCreate.cs index c6f6d4f58..de5f437a8 100644 --- a/src/Artemis.Storage/Migrations/20191013153102_InitialCreate.cs +++ b/src/Artemis.Storage/Migrations/20191028171528_InitialCreate.cs @@ -107,14 +107,11 @@ namespace Artemis.Storage.Migrations }); migrationBuilder.CreateTable( - name: "SurfacePositionEntity", + name: "DeviceEntity", columns: table => new { Guid = table.Column(nullable: false), - DeviceId = table.Column(nullable: false), - DeviceName = table.Column(nullable: true), - DeviceModel = table.Column(nullable: true), - DeviceManufacturer = table.Column(nullable: true), + DeviceHashCode = table.Column(nullable: false), X = table.Column(nullable: false), Y = table.Column(nullable: false), Rotation = table.Column(nullable: false), @@ -123,9 +120,9 @@ namespace Artemis.Storage.Migrations }, constraints: table => { - table.PrimaryKey("PK_SurfacePositionEntity", x => x.Guid); + table.PrimaryKey("PK_DeviceEntity", x => x.Guid); table.ForeignKey( - name: "FK_SurfacePositionEntity_Surfaces_SurfaceId", + name: "FK_DeviceEntity_Surfaces_SurfaceId", column: x => x.SurfaceId, principalTable: "Surfaces", principalColumn: "Guid", @@ -192,6 +189,11 @@ namespace Artemis.Storage.Migrations onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateIndex( + name: "IX_DeviceEntity_SurfaceId", + table: "DeviceEntity", + column: "SurfaceId"); + migrationBuilder.CreateIndex( name: "IX_Folders_FolderEntityGuid", table: "Folders", @@ -221,15 +223,13 @@ namespace Artemis.Storage.Migrations name: "IX_Profiles_RootFolderGuid", table: "Profiles", column: "RootFolderGuid"); - - migrationBuilder.CreateIndex( - name: "IX_SurfacePositionEntity_SurfaceId", - table: "SurfacePositionEntity", - column: "SurfaceId"); } protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "DeviceEntity"); + migrationBuilder.DropTable( name: "Keypoints"); @@ -246,14 +246,11 @@ namespace Artemis.Storage.Migrations name: "Settings"); migrationBuilder.DropTable( - name: "SurfacePositionEntity"); + name: "Surfaces"); migrationBuilder.DropTable( name: "LayerSettings"); - migrationBuilder.DropTable( - name: "Surfaces"); - migrationBuilder.DropTable( name: "Layers"); diff --git a/src/Artemis.Storage/Migrations/StorageContextModelSnapshot.cs b/src/Artemis.Storage/Migrations/StorageContextModelSnapshot.cs index d451cedaf..fbba2e694 100644 --- a/src/Artemis.Storage/Migrations/StorageContextModelSnapshot.cs +++ b/src/Artemis.Storage/Migrations/StorageContextModelSnapshot.cs @@ -16,6 +16,30 @@ namespace Artemis.Storage.Migrations modelBuilder .HasAnnotation("ProductVersion", "2.2.4-servicing-10062"); + modelBuilder.Entity("Artemis.Storage.Entities.DeviceEntity", b => + { + b.Property("Guid") + .ValueGeneratedOnAdd(); + + b.Property("DeviceHashCode"); + + b.Property("Rotation"); + + b.Property("SurfaceId"); + + b.Property("X"); + + b.Property("Y"); + + b.Property("ZIndex"); + + b.HasKey("Guid"); + + b.HasIndex("SurfaceId"); + + b.ToTable("DeviceEntity"); + }); + modelBuilder.Entity("Artemis.Storage.Entities.FolderEntity", b => { b.Property("Guid") @@ -165,34 +189,11 @@ namespace Artemis.Storage.Migrations b.ToTable("Surfaces"); }); - modelBuilder.Entity("Artemis.Storage.Entities.SurfacePositionEntity", b => + modelBuilder.Entity("Artemis.Storage.Entities.DeviceEntity", b => { - b.Property("Guid") - .ValueGeneratedOnAdd(); - - b.Property("DeviceId"); - - b.Property("DeviceManufacturer"); - - b.Property("DeviceModel"); - - b.Property("DeviceName"); - - b.Property("Rotation"); - - b.Property("SurfaceId"); - - b.Property("X"); - - b.Property("Y"); - - b.Property("ZIndex"); - - b.HasKey("Guid"); - - b.HasIndex("SurfaceId"); - - b.ToTable("SurfacePositionEntity"); + b.HasOne("Artemis.Storage.Entities.SurfaceEntity", "Surface") + .WithMany("DeviceEntities") + .HasForeignKey("SurfaceId"); }); modelBuilder.Entity("Artemis.Storage.Entities.FolderEntity", b => @@ -236,13 +237,6 @@ namespace Artemis.Storage.Migrations .WithMany() .HasForeignKey("RootFolderGuid"); }); - - modelBuilder.Entity("Artemis.Storage.Entities.SurfacePositionEntity", b => - { - b.HasOne("Artemis.Storage.Entities.SurfaceEntity", "Surface") - .WithMany("SurfacePositions") - .HasForeignKey("SurfaceId"); - }); #pragma warning restore 612, 618 } } diff --git a/src/Artemis.Storage/Repositories/SurfaceRepository.cs b/src/Artemis.Storage/Repositories/SurfaceRepository.cs index 0d29da7c2..cfd8f3a98 100644 --- a/src/Artemis.Storage/Repositories/SurfaceRepository.cs +++ b/src/Artemis.Storage/Repositories/SurfaceRepository.cs @@ -29,22 +29,22 @@ namespace Artemis.Storage.Repositories public SurfaceEntity Get(string name) { - return _dbContext.Surfaces.Include(s => s.SurfacePositions).FirstOrDefault(p => p.Name == name); + return _dbContext.Surfaces.Include(s => s.DeviceEntities).FirstOrDefault(p => p.Name == name); } public async Task GetAsync(string name) { - return await _dbContext.Surfaces.Include(s => s.SurfacePositions).FirstOrDefaultAsync(p => p.Name == name); + return await _dbContext.Surfaces.Include(s => s.DeviceEntities).FirstOrDefaultAsync(p => p.Name == name); } public List GetAll() { - return _dbContext.Surfaces.Include(s => s.SurfacePositions).ToList(); + return _dbContext.Surfaces.Include(s => s.DeviceEntities).ToList(); } public async Task> GetAllAsync() { - return await _dbContext.Surfaces.Include(s => s.SurfacePositions).ToListAsync(); + return await _dbContext.Surfaces.Include(s => s.DeviceEntities).ToListAsync(); } public void Save() diff --git a/src/Artemis.UI/ViewModels/Controls/SurfaceEditor/SurfaceDeviceViewModel.cs b/src/Artemis.UI/ViewModels/Controls/SurfaceEditor/SurfaceDeviceViewModel.cs index 71f0c6088..6978b91b4 100644 --- a/src/Artemis.UI/ViewModels/Controls/SurfaceEditor/SurfaceDeviceViewModel.cs +++ b/src/Artemis.UI/ViewModels/Controls/SurfaceEditor/SurfaceDeviceViewModel.cs @@ -15,45 +15,45 @@ namespace Artemis.UI.ViewModels.Controls.SurfaceEditor private double _dragOffsetY; private readonly List _leds; - public SurfaceDeviceViewModel(SurfaceDeviceConfiguration deviceConfiguration) + public SurfaceDeviceViewModel(Device device) { - DeviceConfiguration = deviceConfiguration; + Device = device; _leds = new List(); - if (DeviceConfiguration.Device != null) + if (Device.RgbDevice != null) { - foreach (var led in DeviceConfiguration.Device) + foreach (var led in Device.RgbDevice) _leds.Add(new SurfaceLedViewModel(led)); } } - public SurfaceDeviceConfiguration DeviceConfiguration { get; set; } + public Device Device { get; set; } public SelectionStatus SelectionStatus { get; set; } public Cursor Cursor { get; set; } public double X { - get => DeviceConfiguration.X; - set => DeviceConfiguration.X = value; + get => Device.X; + set => Device.X = value; } public double Y { - get => DeviceConfiguration.Y; - set => DeviceConfiguration.Y = value; + get => Device.Y; + set => Device.Y = value; } public int ZIndex { - get => DeviceConfiguration.ZIndex; - set => DeviceConfiguration.ZIndex = value; + get => Device.ZIndex; + set => Device.ZIndex = value; } public IReadOnlyCollection Leds => _leds.AsReadOnly(); - public Rect DeviceRectangle => DeviceConfiguration.Device == null + public Rect DeviceRectangle => Device.RgbDevice == null ? new Rect() - : new Rect(X, Y, DeviceConfiguration.Device.Size.Width, DeviceConfiguration.Device.Size.Height); + : new Rect(X, Y, Device.RgbDevice.Size.Width, Device.RgbDevice.Size.Height); public void StartMouseDrag(Point mouseStartPosition) { diff --git a/src/Artemis.UI/ViewModels/Screens/SettingsViewModel.cs b/src/Artemis.UI/ViewModels/Screens/SettingsViewModel.cs index 432fb0e8e..b55e8b996 100644 --- a/src/Artemis.UI/ViewModels/Screens/SettingsViewModel.cs +++ b/src/Artemis.UI/ViewModels/Screens/SettingsViewModel.cs @@ -1,4 +1,5 @@ using Artemis.Core.Events; +using Artemis.Core.Services; using Artemis.Core.Services.Interfaces; using Artemis.UI.ViewModels.Controls.Settings; using Artemis.UI.ViewModels.Interfaces; @@ -12,7 +13,7 @@ namespace Artemis.UI.ViewModels.Screens private readonly IKernel _kernel; private readonly IWindowManager _windowManager; - public SettingsViewModel(IKernel kernel, IRgbService rgbService, IWindowManager windowManager) + public SettingsViewModel(IKernel kernel, IRgbService rgbService, IWindowManager windowManager, ISettingsService settingsService) { _kernel = kernel; _windowManager = windowManager; diff --git a/src/Artemis.UI/ViewModels/Screens/SurfaceEditorViewModel.cs b/src/Artemis.UI/ViewModels/Screens/SurfaceEditorViewModel.cs index d247a1d60..913b692dc 100644 --- a/src/Artemis.UI/ViewModels/Screens/SurfaceEditorViewModel.cs +++ b/src/Artemis.UI/ViewModels/Screens/SurfaceEditorViewModel.cs @@ -25,7 +25,7 @@ namespace Artemis.UI.ViewModels.Screens public SurfaceEditorViewModel(ISurfaceService surfaceService, IDialogService dialogService) { Devices = new ObservableCollection(); - SurfaceConfigurations = new ObservableCollection(); + SurfaceConfigurations = new ObservableCollection(); SelectionRectangle = new RectangleGeometry(); PanZoomViewModel = new PanZoomViewModel(); @@ -35,14 +35,14 @@ namespace Artemis.UI.ViewModels.Screens public RectangleGeometry SelectionRectangle { get; set; } public ObservableCollection Devices { get; set; } - public ObservableCollection SurfaceConfigurations { get; set; } + public ObservableCollection SurfaceConfigurations { get; set; } - public SurfaceConfiguration SelectedSurfaceConfiguration + public Surface SelectedSurface { - get => _selectedSurfaceConfiguration; + get => _selectedSurface; set { - _selectedSurfaceConfiguration = value; + _selectedSurface = value; ApplySelectedSurfaceConfiguration(); } } @@ -50,7 +50,7 @@ namespace Artemis.UI.ViewModels.Screens public PanZoomViewModel PanZoomViewModel { get; set; } public string Title => "Surface Editor"; - public SurfaceConfiguration CreateSurfaceConfiguration(string name) + public Surface CreateSurfaceConfiguration(string name) { var config = _surfaceService.CreateSurfaceConfiguration(name); Execute.OnUIThread(() => SurfaceConfigurations.Add(config)); @@ -63,7 +63,7 @@ namespace Artemis.UI.ViewModels.Screens var configs = _surfaceService.SurfaceConfigurations; // Get the active config, if empty, create a default config - var activeConfig = _surfaceService.ActiveSurfaceConfiguration; + var activeConfig = _surfaceService.ActiveSurface; if (activeConfig == null) { activeConfig = CreateSurfaceConfiguration("Default"); @@ -78,31 +78,31 @@ namespace Artemis.UI.ViewModels.Screens SurfaceConfigurations.Add(surfaceConfiguration); // Set the active config - SelectedSurfaceConfiguration = activeConfig; + SelectedSurface = activeConfig; }); } private void ApplySelectedSurfaceConfiguration() { - if (SelectedSurfaceConfiguration == null) + if (SelectedSurface == null) { Execute.OnUIThread(Devices.Clear); return; } // Make sure all devices have an up-to-date VM - foreach (var surfaceDeviceConfiguration in SelectedSurfaceConfiguration.DeviceConfigurations) + foreach (var surfaceDeviceConfiguration in SelectedSurface.Devices) { // Create VMs for missing devices - var viewModel = Devices.FirstOrDefault(vm => vm.DeviceConfiguration.Device == surfaceDeviceConfiguration.Device); + var viewModel = Devices.FirstOrDefault(vm => vm.Device.RgbDevice == surfaceDeviceConfiguration.RgbDevice); if (viewModel == null) Execute.OnUIThread(() => Devices.Add(new SurfaceDeviceViewModel(surfaceDeviceConfiguration))); // Update existing devices else - viewModel.DeviceConfiguration = surfaceDeviceConfiguration; + viewModel.Device = surfaceDeviceConfiguration; } - _surfaceService.SetActiveSurfaceConfiguration(SelectedSurfaceConfiguration); + _surfaceService.SetActiveSurfaceConfiguration(SelectedSurface); } #region Overrides of Screen @@ -117,7 +117,7 @@ namespace Artemis.UI.ViewModels.Screens #region Configuration management - public async Task DeleteSurfaceConfiguration(SurfaceConfiguration surfaceConfiguration) + public async Task DeleteSurfaceConfiguration(Surface surface) { var result = await _dialogService.ShowConfirmDialogAt( "SurfaceListDialogHost", @@ -126,8 +126,8 @@ namespace Artemis.UI.ViewModels.Screens ); if (result) { - SurfaceConfigurations.Remove(surfaceConfiguration); - _surfaceService.DeleteSurfaceConfiguration(surfaceConfiguration); + SurfaceConfigurations.Remove(surface); + _surfaceService.DeleteSurfaceConfiguration(surface); } } @@ -189,11 +189,11 @@ namespace Artemis.UI.ViewModels.Screens #endregion - #region Device selection + #region RgbDevice selection private MouseDragStatus _mouseDragStatus; private Point _mouseDragStartPoint; - private SurfaceConfiguration _selectedSurfaceConfiguration; + private Surface _selectedSurface; // ReSharper disable once UnusedMember.Global - Called from view public void EditorGridMouseClick(object sender, MouseEventArgs e) @@ -280,7 +280,7 @@ namespace Artemis.UI.ViewModels.Screens } } else - _surfaceService.UpdateSurfaceConfiguration(SelectedSurfaceConfiguration, true); + _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); Mouse.OverrideCursor = null; _mouseDragStatus = MouseDragStatus.None; diff --git a/src/Artemis.UI/Views/Controls/SurfaceEditor/SurfaceDeviceView.xaml b/src/Artemis.UI/Views/Controls/SurfaceEditor/SurfaceDeviceView.xaml index ac52a02f9..f22c4dc3b 100644 --- a/src/Artemis.UI/Views/Controls/SurfaceEditor/SurfaceDeviceView.xaml +++ b/src/Artemis.UI/Views/Controls/SurfaceEditor/SurfaceDeviceView.xaml @@ -13,20 +13,20 @@ Cursor="{Binding Cursor}" MouseEnter="{s:Action MouseEnter}" MouseLeave="{s:Action MouseLeave}" - ToolTip="{Binding DeviceConfiguration.Device.DeviceInfo.DeviceName}"> + ToolTip="{Binding Device.RgbDevice.DeviceInfo.DeviceName}"> - + - + - - General - - General settings like start up with Windows etc. + + + General + + General settings like start up with Windows etc. - + + + + Devices + + A list of devices and options to disable them + + + + + + + + + + + + + + + + Plugins + + A list of plugins and options to disable them + - - Devices - - A list of devices and options to disable them - - - - - - - - - - - - - - - - Plugins - - A list of plugins and options to disable them - - + + \ No newline at end of file diff --git a/src/Artemis.UI/Views/Screens/SurfaceEditorView.xaml b/src/Artemis.UI/Views/Screens/SurfaceEditorView.xaml index d9aaac840..e73416086 100644 --- a/src/Artemis.UI/Views/Screens/SurfaceEditorView.xaml +++ b/src/Artemis.UI/Views/Screens/SurfaceEditorView.xaml @@ -108,8 +108,8 @@ - @@ -183,9 +183,9 @@ - + - +