From 9f8fc9f70e8ee06336aa0f1831aca33a64c0f386 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Tue, 21 Apr 2020 19:59:05 +0200 Subject: [PATCH] Core - Add HidSharp to force plugins to share the HidSharp types Core - For now, set default log level to debug ColorGradient- Improved GetColor performance ColorGradient - GetColor now handles colors not between two stops properly Home - Fix links Plugins - Only allow layer property registration through Brushes Color brush - Default to solid color --- src/Artemis.Core/Artemis.Core.csproj | 1 + .../Models/Profile/ColorGradient.cs | 93 ++++++++------- .../LayerPropertyCollection.cs | 58 ++++----- .../Plugins/LayerBrush/LayerBrush.cs | 19 ++- src/Artemis.Core/Services/CoreService.cs | 2 +- .../Services/Interfaces/IRgbService.cs | 2 + src/Artemis.Core/Services/RgbService.cs | 14 +-- .../Services/Storage/SurfaceService.cs | 1 + .../Artemis.UI.Shared.csproj | 1 + src/Artemis.UI.Shared/FodyWeavers.xml | 3 + src/Artemis.UI.Shared/FodyWeavers.xsd | 64 ++++++++++ .../GradientEditor/GradientEditorView.xaml | 9 +- .../GradientEditor/GradientEditorViewModel.cs | 16 ++- .../Services/GradientPickerService.cs | 9 +- src/Artemis.UI/Screens/Home/HomeViewModel.cs | 5 +- .../LayerPropertiesViewModel.cs | 2 +- .../PropertyInput/PropertyInputViewModel.cs | 2 +- .../SurfaceEditor/SurfaceEditorViewModel.cs | 30 +++-- ...Artemis.Plugins.Devices.SteelSeries.csproj | 2 +- .../ColorBrush.cs | 111 +++++++++--------- .../NoiseBrush.cs | 7 +- 21 files changed, 279 insertions(+), 172 deletions(-) create mode 100644 src/Artemis.UI.Shared/FodyWeavers.xml create mode 100644 src/Artemis.UI.Shared/FodyWeavers.xsd diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 0ae5dbd13..3a632ed07 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -22,6 +22,7 @@ + diff --git a/src/Artemis.Core/Models/Profile/ColorGradient.cs b/src/Artemis.Core/Models/Profile/ColorGradient.cs index 6f5e0ec41..7414f13ef 100644 --- a/src/Artemis.Core/Models/Profile/ColorGradient.cs +++ b/src/Artemis.Core/Models/Profile/ColorGradient.cs @@ -28,6 +28,54 @@ namespace Artemis.Core.Models.Profile return Stops.OrderBy(c => c.Position).Select(c => c.Position).ToArray(); } + public void OnColorValuesUpdated() + { + OnPropertyChanged(nameof(Stops)); + } + + public SKColor GetColor(float position) + { + if (!Stops.Any()) + return SKColor.Empty; + + var stops = Stops.OrderBy(x => x.Position).ToArray(); + if (position <= 0) return stops[0].Color; + if (position >= 1) return stops[^1].Color; + ColorGradientStop left = stops[0], right = null; + foreach (var stop in stops) + { + if (stop.Position >= position) + { + right = stop; + break; + } + + left = stop; + } + + if (right == null || left == right) + return left.Color; + + position = (float) Math.Round((position - left.Position) / (right.Position - left.Position), 2); + var a = (byte) ((right.Color.Alpha - left.Color.Alpha) * position + left.Color.Alpha); + var r = (byte) ((right.Color.Red - left.Color.Red) * position + left.Color.Red); + var g = (byte) ((right.Color.Green - left.Color.Green) * position + left.Color.Green); + var b = (byte) ((right.Color.Blue - left.Color.Blue) * position + left.Color.Blue); + return new SKColor(r, g, b, a); + } + + /// + /// [PH] Looping through HSV, adds 8 rainbow colors + /// + public void MakeFabulous() + { + for (var i = 0; i < 9; i++) + { + var color = i != 8 ? SKColor.FromHsv(i * 32, 100, 100) : SKColor.FromHsv(0, 100, 100); + Stops.Add(new ColorGradientStop(color, 0.125f * i)); + } + } + #region PropertyChanged public event PropertyChangedEventHandler PropertyChanged; @@ -39,51 +87,6 @@ namespace Artemis.Core.Models.Profile } #endregion - - public void OnColorValuesUpdated() - { - OnPropertyChanged(nameof(Stops)); - } - - public SKColor GetColor(float position) - { - if (!Stops.Any()) - return SKColor.Empty; - - var point = Stops.FirstOrDefault(f => f.Position == position); - if (point != null) return point.Color; - - var before = Stops.First(w => w.Position == Stops.Min(m => m.Position)); - var after = Stops.First(w => w.Position == Stops.Max(m => m.Position)); - - foreach (var gs in Stops) - { - if (gs.Position < position && gs.Position > before.Position) - before = gs; - - if (gs.Position >= position && gs.Position < after.Position) - after = gs; - } - - return new SKColor( - (byte) ((position - before.Position) * (after.Color.Red - before.Color.Red) / (after.Position - before.Position) + before.Color.Red), - (byte) ((position - before.Position) * (after.Color.Green - before.Color.Green) / (after.Position - before.Position) + before.Color.Green), - (byte) ((position - before.Position) * (after.Color.Blue - before.Color.Blue) / (after.Position - before.Position) + before.Color.Blue), - (byte) ((position - before.Position) * (after.Color.Alpha - before.Color.Alpha) / (after.Position - before.Position) + before.Color.Alpha) - ); - } - - /// - /// [PH] Looping through HSV, adds 8 rainbow colors - /// - public void MakeFabulous() - { - for (var i = 0; i < 9; i++) - { - var color = i != 8 ? SKColor.FromHsv(i * 32, 100, 100) : SKColor.FromHsv(0, 100, 100); - Stops.Add(new ColorGradientStop(color, 0.125f * i)); - } - } } public class ColorGradientStop : INotifyPropertyChanged diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyCollection.cs b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyCollection.cs index b8283a1aa..80b5a65e6 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyCollection.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/LayerPropertyCollection.cs @@ -41,32 +41,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties return GetEnumerator(); } - /// - /// Removes the provided layer property from the layer. - /// - /// The type of value of the layer property - /// The property to remove from the layer - public void RemoveLayerProperty(LayerProperty layerProperty) - { - RemoveLayerProperty((BaseLayerProperty) layerProperty); - } - - /// - /// Removes the provided layer property from the layer. - /// - /// The property to remove from the layer - public void RemoveLayerProperty(BaseLayerProperty layerProperty) - { - if (!_properties.ContainsKey((layerProperty.PluginInfo.Guid, layerProperty.Id))) - throw new ArtemisCoreException($"Could not find a property with ID {layerProperty.Id}."); - - var property = _properties[(layerProperty.PluginInfo.Guid, layerProperty.Id)]; - property.Parent?.Children.Remove(property); - _properties.Remove((layerProperty.PluginInfo.Guid, layerProperty.Id)); - - OnLayerPropertyRemoved(new LayerPropertyEventArgs(property)); - } - /// /// If found, returns the matching the provided ID /// @@ -82,7 +56,33 @@ namespace Artemis.Core.Models.Profile.LayerProperties var property = _properties[(pluginInfo.Guid, id)]; if (property.Type != typeof(T)) throw new ArtemisCoreException($"Property type mismatch. Expected property {property} to have type {typeof(T)} but it has {property.Type} instead."); - return (LayerProperty) _properties[(pluginInfo.Guid, id)]; + return (LayerProperty)_properties[(pluginInfo.Guid, id)]; + } + + /// + /// Removes the provided layer property from the layer. + /// + /// The type of value of the layer property + /// The property to remove from the layer + internal void RemoveLayerProperty(LayerProperty layerProperty) + { + RemoveLayerProperty((BaseLayerProperty) layerProperty); + } + + /// + /// Removes the provided layer property from the layer. + /// + /// The property to remove from the layer + internal void RemoveLayerProperty(BaseLayerProperty layerProperty) + { + if (!_properties.ContainsKey((layerProperty.PluginInfo.Guid, layerProperty.Id))) + throw new ArtemisCoreException($"Could not find a property with ID {layerProperty.Id}."); + + var property = _properties[(layerProperty.PluginInfo.Guid, layerProperty.Id)]; + property.Parent?.Children.Remove(property); + _properties.Remove((layerProperty.PluginInfo.Guid, layerProperty.Id)); + + OnLayerPropertyRemoved(new LayerPropertyEventArgs(property)); } /// @@ -92,7 +92,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// The type of value of the layer property /// The property to apply to the layer /// True if an existing value was found and applied, otherwise false. - public bool RegisterLayerProperty(LayerProperty layerProperty) + internal bool RegisterLayerProperty(LayerProperty layerProperty) { return RegisterLayerProperty((BaseLayerProperty) layerProperty); } @@ -103,7 +103,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// /// The property to apply to the layer /// True if an existing value was found and applied, otherwise false. - public bool RegisterLayerProperty(BaseLayerProperty layerProperty) + internal bool RegisterLayerProperty(BaseLayerProperty layerProperty) { if (_properties.ContainsKey((layerProperty.PluginInfo.Guid, layerProperty.Id))) throw new ArtemisCoreException($"Duplicate property ID detected. Layer already contains a property with ID {layerProperty.Id}."); diff --git a/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs index 0ebbb4194..bd83f5f8e 100644 --- a/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrush/LayerBrush.cs @@ -2,6 +2,7 @@ using System.Linq; using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile.LayerProperties; +using Artemis.Core.Plugins.Exceptions; using Artemis.Core.Services.Interfaces; using SkiaSharp; @@ -35,7 +36,7 @@ namespace Artemis.Core.Plugins.LayerBrush /// /// The main method of rendering anything to the layer. The provided is specific to the layer /// and matches it's width and height. - /// Called during rendering, in the order configured on the layer + /// Called during rendering or layer preview, in the order configured on the layer /// /// The layer canvas /// @@ -77,6 +78,22 @@ namespace Artemis.Core.Plugins.LayerBrush /// The layer property protected LayerProperty RegisterLayerProperty(string id, string name, string description, T defaultValue = default) { + // Check if the property already exists + var existing = Layer.Properties.FirstOrDefault(p => + p.PluginInfo.Guid == Descriptor.LayerBrushProvider.PluginInfo.Guid && + p.Id == id && + p.Name == name && + p.Description == description); + + if (existing != null) + { + // If it exists and the types match, return the existing property + if (existing.Type == typeof(T)) + return (LayerProperty) existing; + // If it exists and the types are different, something is wrong + throw new ArtemisPluginException($"Cannot register the property {id} with different types twice."); + } + var property = new LayerProperty(Layer, Descriptor.LayerBrushProvider.PluginInfo, Layer.Properties.BrushReference.Parent, id, name, description) { Value = defaultValue diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index e225a8823..896186074 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -38,7 +38,7 @@ namespace Artemis.Core.Services _rgbService = rgbService; _surfaceService = surfaceService; _profileService = profileService; - _loggingLevel = settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information); + _loggingLevel = settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Debug); _rgbService.Surface.Updating += SurfaceOnUpdating; _rgbService.Surface.Updated += SurfaceOnUpdated; diff --git a/src/Artemis.Core/Services/Interfaces/IRgbService.cs b/src/Artemis.Core/Services/Interfaces/IRgbService.cs index a7885911d..e7304a8c1 100644 --- a/src/Artemis.Core/Services/Interfaces/IRgbService.cs +++ b/src/Artemis.Core/Services/Interfaces/IRgbService.cs @@ -28,6 +28,8 @@ namespace Artemis.Core.Services.Interfaces /// IReadOnlyCollection LoadedDevices { get; } + TimerUpdateTrigger UpdateTrigger { get; } + /// /// Adds the given device provider to the /// diff --git a/src/Artemis.Core/Services/RgbService.cs b/src/Artemis.Core/Services/RgbService.cs index 6534bd656..f6c8c43ad 100644 --- a/src/Artemis.Core/Services/RgbService.cs +++ b/src/Artemis.Core/Services/RgbService.cs @@ -20,7 +20,6 @@ namespace Artemis.Core.Services private readonly PluginSetting _renderScaleSetting; private readonly PluginSetting _sampleSizeSetting; private readonly PluginSetting _targetFrameRateSetting; - private readonly TimerUpdateTrigger _updateTrigger; private ListLedGroup _surfaceLedGroup; internal RgbService(ILogger logger, ISettingsService settingsService) @@ -37,17 +36,16 @@ namespace Artemis.Core.Services _renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged; _targetFrameRateSetting.SettingChanged += TargetFrameRateSettingOnSettingChanged; _loadedDevices = new List(); - _updateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value}; - Surface.RegisterUpdateTrigger(_updateTrigger); + UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value}; + Surface.RegisterUpdateTrigger(UpdateTrigger); } /// public RGBSurface Surface { get; set; } + public TimerUpdateTrigger UpdateTrigger { get; } public BitmapBrush BitmapBrush { get; private set; } - public IReadOnlyCollection LoadedDevices => _loadedDevices.AsReadOnly(); - public double RenderScale => _renderScaleSetting.Value; public void AddDeviceProvider(IRGBDeviceProvider deviceProvider) @@ -82,9 +80,9 @@ namespace Artemis.Core.Services public void Dispose() { - Surface.UnregisterUpdateTrigger(_updateTrigger); + Surface.UnregisterUpdateTrigger(UpdateTrigger); - _updateTrigger.Dispose(); + UpdateTrigger.Dispose(); Surface.Dispose(); } @@ -95,7 +93,7 @@ namespace Artemis.Core.Services private void TargetFrameRateSettingOnSettingChanged(object sender, EventArgs e) { - _updateTrigger.UpdateFrequency = 1.0 / _targetFrameRateSetting.Value; + UpdateTrigger.UpdateFrequency = 1.0 / _targetFrameRateSetting.Value; } private void SurfaceOnException(ExceptionEventArgs args) diff --git a/src/Artemis.Core/Services/Storage/SurfaceService.cs b/src/Artemis.Core/Services/Storage/SurfaceService.cs index dc4dc2145..f394f7068 100644 --- a/src/Artemis.Core/Services/Storage/SurfaceService.cs +++ b/src/Artemis.Core/Services/Storage/SurfaceService.cs @@ -95,6 +95,7 @@ namespace Artemis.Core.Services.Storage // Update the RGB service's graphics decorator to work with the new surface entity _rgbService.UpdateSurfaceLedGroup(); OnActiveSurfaceConfigurationChanged(new SurfaceConfigurationEventArgs(ActiveSurface)); + } public void UpdateSurfaceConfiguration(ArtemisSurface surface, bool includeDevices) diff --git a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj index d09cfde49..f25f3f433 100644 --- a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj +++ b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj @@ -25,6 +25,7 @@ + diff --git a/src/Artemis.UI.Shared/FodyWeavers.xml b/src/Artemis.UI.Shared/FodyWeavers.xml new file mode 100644 index 000000000..d5abfed81 --- /dev/null +++ b/src/Artemis.UI.Shared/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Artemis.UI.Shared/FodyWeavers.xsd b/src/Artemis.UI.Shared/FodyWeavers.xsd new file mode 100644 index 000000000..221aeb8a5 --- /dev/null +++ b/src/Artemis.UI.Shared/FodyWeavers.xsd @@ -0,0 +1,64 @@ + + + + + + + + + + + Used to control if the On_PropertyName_Changed feature is enabled. + + + + + Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form. + + + + + Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project. + + + + + Used to control if equality checks should use the Equals method resolved from the base class. + + + + + Used to control if equality checks should use the static Equals method resolved from the base class. + + + + + Used to turn off build warnings from this weaver. + + + + + Used to turn off build warnings about mismatched On_PropertyName_Changed methods. + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorView.xaml b/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorView.xaml index 6e972254f..e08eb0abd 100644 --- a/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorView.xaml +++ b/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorView.xaml @@ -10,6 +10,7 @@ xmlns:shared="clr-namespace:Artemis.UI.Shared" xmlns:s="https://github.com/canton7/Stylet" xmlns:controls1="clr-namespace:Artemis.UI.Shared.Controls" + xmlns:utilities="clr-namespace:Artemis.UI.Shared.Utilities" mc:Ignorable="d" Background="{DynamicResource MaterialDesignPaper}" FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto" @@ -22,13 +23,13 @@ - + - + Gradient - + diff --git a/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorViewModel.cs b/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorViewModel.cs index 94a01c435..f80008f53 100644 --- a/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorViewModel.cs +++ b/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorViewModel.cs @@ -7,15 +7,14 @@ using System.Windows.Input; using Artemis.Core.Models.Profile; using Artemis.UI.Shared.Services.Dialog; using Artemis.UI.Shared.Utilities; -using SkiaSharp; using Stylet; namespace Artemis.UI.Shared.Screens.GradientEditor { public class GradientEditorViewModel : DialogViewModelBase { - private ColorStopViewModel _selectedColorStopViewModel; private readonly List _originalStops; + private ColorStopViewModel _selectedColorStopViewModel; public GradientEditorViewModel(ColorGradient colorGradient) { @@ -24,8 +23,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor _originalStops = ColorGradient.Stops.Select(s => new ColorGradientStop(s.Color, s.Position)).ToList(); - foreach (var colorStop in ColorGradient.Stops.OrderBy(s => s.Position)) - ColorStopViewModels.Add(new ColorStopViewModel(this, colorStop)); + PropertyChanged += UpdateColorStopViewModels; } public BindableCollection ColorStopViewModels { get; set; } @@ -43,8 +41,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor public bool HasSelectedColorStopViewModel => SelectedColorStopViewModel != null; public ColorGradient ColorGradient { get; } - // TODO: Find the width out from view - public double PreviewWidth => 408; + public double PreviewWidth { get; set; } public void AddColorStop(object sender, MouseEventArgs e) { @@ -99,5 +96,12 @@ namespace Artemis.UI.Shared.Screens.GradientEditor if (!Session.IsEnded) Session.Close(false); } + + private void UpdateColorStopViewModels(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != nameof(PreviewWidth)) return; + foreach (var colorStop in ColorGradient.Stops.OrderBy(s => s.Position)) + ColorStopViewModels.Add(new ColorStopViewModel(this, colorStop)); + } } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/GradientPickerService.cs b/src/Artemis.UI.Shared/Services/GradientPickerService.cs index a0b3eb5d8..012aedad5 100644 --- a/src/Artemis.UI.Shared/Services/GradientPickerService.cs +++ b/src/Artemis.UI.Shared/Services/GradientPickerService.cs @@ -1,23 +1,16 @@ using System.Collections.Generic; using Artemis.Core.Models.Profile; -using Artemis.UI.Shared.Ninject.Factories; using Artemis.UI.Shared.Screens.GradientEditor; using Artemis.UI.Shared.Services.Interfaces; -using LiteDB.Engine; -using Ninject; -using Stylet; namespace Artemis.UI.Shared.Services { public class GradientPickerService : IGradientPickerService { - private readonly IGradientEditorVmFactory _gradientEditorVmFactory; private readonly IDialogService _dialogService; - private readonly IWindowManager _windowManager; - public GradientPickerService(IGradientEditorVmFactory gradientEditorVmFactory, IDialogService dialogService) + public GradientPickerService(IDialogService dialogService) { - _gradientEditorVmFactory = gradientEditorVmFactory; _dialogService = dialogService; } diff --git a/src/Artemis.UI/Screens/Home/HomeViewModel.cs b/src/Artemis.UI/Screens/Home/HomeViewModel.cs index 5fa9f7921..71603f97d 100644 --- a/src/Artemis.UI/Screens/Home/HomeViewModel.cs +++ b/src/Artemis.UI/Screens/Home/HomeViewModel.cs @@ -14,7 +14,10 @@ namespace Artemis.UI.Screens.Home { // Don't open anything but valid URIs if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute)) - Process.Start(url); + { + url = url.Replace("&", "^&"); + Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") {CreateNoWindow = true}); + } } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs index 9170409df..3be5e163d 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs @@ -261,7 +261,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties { // End time is the last keyframe + 10 sec var lastKeyFrame = PropertyTimeline.PropertyTrackViewModels.SelectMany(r => r.KeyframeViewModels).OrderByDescending(t => t.Keyframe.Position).FirstOrDefault(); - return lastKeyFrame?.Keyframe.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.FromSeconds(10); + return lastKeyFrame?.Keyframe.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.MaxValue; } private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e) diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs index 3ec4127b4..42b6e9678 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/PropertyTree/PropertyInput/PropertyInputViewModel.cs @@ -51,7 +51,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P { } - private void LayerPropertyOnValueChanged(object? sender, EventArgs e) + private void LayerPropertyOnValueChanged(object sender, EventArgs e) { Update(); } diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs index 06ac81dc9..28be18a9b 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs @@ -10,6 +10,7 @@ using System.Windows.Media; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; using Artemis.Core.Services; +using Artemis.Core.Services.Interfaces; using Artemis.Core.Services.Storage.Interfaces; using Artemis.UI.Screens.Shared; using Artemis.UI.Screens.SurfaceEditor.Dialogs; @@ -24,9 +25,11 @@ namespace Artemis.UI.Screens.SurfaceEditor private readonly IDeviceService _deviceService; private readonly IDialogService _dialogService; private readonly ISettingsService _settingsService; + private readonly IRgbService _rgbService; private readonly ISurfaceService _surfaceService; - public SurfaceEditorViewModel(ISurfaceService surfaceService, IDialogService dialogService, ISettingsService settingsService, IDeviceService deviceService) + public SurfaceEditorViewModel(IRgbService rgbService, ISurfaceService surfaceService, IDialogService dialogService, ISettingsService settingsService, + IDeviceService deviceService) { DisplayName = "Surface Editor"; @@ -36,6 +39,7 @@ namespace Artemis.UI.Screens.SurfaceEditor PanZoomViewModel = new PanZoomViewModel(); Cursor = null; + _rgbService = rgbService; _surfaceService = surfaceService; _dialogService = dialogService; _settingsService = settingsService; @@ -90,7 +94,9 @@ namespace Artemis.UI.Screens.SurfaceEditor { activeConfig = CreateSurfaceConfiguration("Default"); configs.Add(activeConfig); + _rgbService.UpdateTrigger.Stop(); _surfaceService.SetActiveSurfaceConfiguration(activeConfig); + _rgbService.UpdateTrigger.Start(); } Execute.PostToUIThread(() => @@ -134,7 +140,9 @@ namespace Artemis.UI.Screens.SurfaceEditor } }); + _rgbService.UpdateTrigger.Stop(); _surfaceService.SetActiveSurfaceConfiguration(SelectedSurface); + _rgbService.UpdateTrigger.Start(); } #region Overrides of Screen @@ -195,7 +203,7 @@ namespace Artemis.UI.Screens.SurfaceEditor deviceViewModel.Device.ZIndex = i + 1; } - _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); + SafeUpdateSurfaceConfiguration(); } public void BringForward(SurfaceDeviceViewModel surfaceDeviceViewModel) @@ -210,7 +218,7 @@ namespace Artemis.UI.Screens.SurfaceEditor deviceViewModel.Device.ZIndex = i + 1; } - _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); + SafeUpdateSurfaceConfiguration(); } public void SendToBack(SurfaceDeviceViewModel surfaceDeviceViewModel) @@ -222,7 +230,7 @@ namespace Artemis.UI.Screens.SurfaceEditor deviceViewModel.Device.ZIndex = i + 1; } - _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); + SafeUpdateSurfaceConfiguration(); } public void SendBackward(SurfaceDeviceViewModel surfaceDeviceViewModel) @@ -236,7 +244,7 @@ namespace Artemis.UI.Screens.SurfaceEditor deviceViewModel.Device.ZIndex = i + 1; } - _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); + SafeUpdateSurfaceConfiguration(); } public async Task ViewProperties(SurfaceDeviceViewModel surfaceDeviceViewModel) @@ -247,7 +255,7 @@ namespace Artemis.UI.Screens.SurfaceEditor }); if ((bool) madeChanges) - _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); + SafeUpdateSurfaceConfiguration(); } #endregion @@ -343,8 +351,7 @@ namespace Artemis.UI.Screens.SurfaceEditor } } else - _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); - + SafeUpdateSurfaceConfiguration(); _mouseDragStatus = MouseDragStatus.None; } @@ -372,6 +379,13 @@ namespace Artemis.UI.Screens.SurfaceEditor device.UpdateMouseDrag(position); } + private void SafeUpdateSurfaceConfiguration() + { + _rgbService.UpdateTrigger.Stop(); + _surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true); + _rgbService.UpdateTrigger.Start(); + } + #endregion #region Panning and zooming diff --git a/src/Plugins/Artemis.Plugins.Devices.SteelSeries/Artemis.Plugins.Devices.SteelSeries.csproj b/src/Plugins/Artemis.Plugins.Devices.SteelSeries/Artemis.Plugins.Devices.SteelSeries.csproj index b2913659d..6d43ba194 100644 --- a/src/Plugins/Artemis.Plugins.Devices.SteelSeries/Artemis.Plugins.Devices.SteelSeries.csproj +++ b/src/Plugins/Artemis.Plugins.Devices.SteelSeries/Artemis.Plugins.Devices.SteelSeries.csproj @@ -21,7 +21,7 @@ - + diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/ColorBrush.cs b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/ColorBrush.cs index b4417aef9..14bf9d89c 100644 --- a/src/Plugins/Artemis.Plugins.LayerBrushes.Color/ColorBrush.cs +++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Color/ColorBrush.cs @@ -17,50 +17,27 @@ namespace Artemis.Plugins.LayerBrushes.Color public ColorBrush(Layer layer, LayerBrushDescriptor descriptor) : base(layer, descriptor) { - GradientTypeProperty = RegisterLayerProperty("Brush.GradientType", "Gradient type", "The type of color brush to draw"); + GradientTypeProperty = RegisterLayerProperty("Brush.GradientType", "Gradient type", "The type of color brush to draw", GradientType.Solid); GradientTypeProperty.CanUseKeyframes = false; UpdateColorProperties(); - Layer.RenderPropertiesUpdated += (sender, args) => CreateShader(_shaderBounds); + Layer.RenderPropertiesUpdated += (sender, args) => CreateShader(); GradientTypeProperty.ValueChanged += (sender, args) => UpdateColorProperties(); } - private void UpdateColorProperties() - { - UnRegisterLayerProperty(ColorProperty); - ColorProperty = null; - UnRegisterLayerProperty(GradientProperty); - GradientProperty = null; - - if (GradientTypeProperty.Value == GradientType.Solid) - { - ColorProperty = RegisterLayerProperty("Brush.Color", "Color", "The color of the brush", new SKColor(255, 0, 0)); - ColorProperty.ValueChanged += (sender, args) => CreateShader(_shaderBounds); - } - else - { - GradientProperty = RegisterLayerProperty("Brush.Gradient", "Gradient", "The gradient of the brush", new ColorGradient()); - GradientProperty.Value.PropertyChanged += (sender, args) => CreateShader(_shaderBounds); - - if (!GradientProperty.Value.Stops.Any()) - GradientProperty.Value.MakeFabulous(); - } - - CreateShader(_shaderBounds); - } - public LayerProperty ColorProperty { get; set; } public LayerProperty GradientProperty { get; set; } public LayerProperty GradientTypeProperty { get; set; } public override void Update(double deltaTime) { - // Only recreate the shader if the color changed - if (ColorProperty != null && _color != ColorProperty.CurrentValue) + // Only check if a solid is being drawn, because that can be changed by keyframes + if (GradientTypeProperty.Value == GradientType.Solid && _color != ColorProperty.CurrentValue) { + // If the color was changed since the last frame, recreate the shader _color = ColorProperty.CurrentValue; - CreateShader(_shaderBounds); + CreateShader(); } base.Update(deltaTime); @@ -69,45 +46,69 @@ namespace Artemis.Plugins.LayerBrushes.Color public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint) { if (path.Bounds != _shaderBounds) - CreateShader(path.Bounds); + { + _shaderBounds = path.Bounds; + CreateShader(); + } paint.Shader = _shader; canvas.DrawPath(path, paint); } - private void CreateShader(SKRect pathBounds) + private void UpdateColorProperties() { - var center = new SKPoint(pathBounds.MidX, pathBounds.MidY); - SKShader shader; - switch (GradientTypeProperty.CurrentValue) + if (GradientTypeProperty.Value == GradientType.Solid) { - case GradientType.Solid: - shader = SKShader.CreateColor(_color); - break; - case GradientType.LinearGradient: - shader = SKShader.CreateLinearGradient(new SKPoint(pathBounds.Left, pathBounds.Top), new SKPoint(pathBounds.Right, pathBounds.Bottom), - GradientProperty.Value.GetColorsArray(), - GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Repeat); - break; - case GradientType.RadialGradient: - shader = SKShader.CreateRadialGradient(center, Math.Min(pathBounds.Width, pathBounds.Height), - GradientProperty.Value.GetColorsArray(), - GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Repeat); - break; - case GradientType.SweepGradient: - shader = SKShader.CreateSweepGradient(center, - GradientProperty.Value.GetColorsArray(), - GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Clamp, 0, 360); - break; - default: - throw new ArgumentOutOfRangeException(); + UnRegisterLayerProperty(GradientProperty); + ColorProperty = RegisterLayerProperty("Brush.Color", "Color", "The color of the brush", new SKColor(255, 0, 0)); + ColorProperty.ValueChanged += (sender, args) => CreateShader(); } + else + { + UnRegisterLayerProperty(ColorProperty); + GradientProperty = RegisterLayerProperty("Brush.Gradient", "Gradient", "The gradient of the brush", new ColorGradient()); + GradientProperty.CanUseKeyframes = false; + GradientProperty.Value.PropertyChanged += (sender, args) => CreateShader(); + + if (!GradientProperty.Value.Stops.Any()) + GradientProperty.Value.MakeFabulous(); + } + + CreateShader(); + } + + private void CreateShader() + { + var center = new SKPoint(_shaderBounds.MidX, _shaderBounds.MidY); + var shader = GradientTypeProperty.CurrentValue switch + { + GradientType.Solid => SKShader.CreateColor(_color), + GradientType.LinearGradient => SKShader.CreateLinearGradient( + new SKPoint(_shaderBounds.Left, _shaderBounds.Top), + new SKPoint(_shaderBounds.Right, _shaderBounds.Bottom), + GradientProperty.Value.GetColorsArray(), + GradientProperty.Value.GetPositionsArray(), + SKShaderTileMode.Repeat), + GradientType.RadialGradient => SKShader.CreateRadialGradient( + center, + Math.Min(_shaderBounds.Width, _shaderBounds.Height), + GradientProperty.Value.GetColorsArray(), + GradientProperty.Value.GetPositionsArray(), + SKShaderTileMode.Repeat), + GradientType.SweepGradient => SKShader.CreateSweepGradient( + center, + GradientProperty.Value.GetColorsArray(), + GradientProperty.Value.GetPositionsArray(), + SKShaderTileMode.Clamp, + 0, + 360), + _ => throw new ArgumentOutOfRangeException() + }; var oldShader = _shader; var oldPaint = _paint; _shader = shader; _paint = new SKPaint {Shader = _shader, FilterQuality = SKFilterQuality.Low}; - _shaderBounds = pathBounds; oldShader?.Dispose(); oldPaint?.Dispose(); } diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs b/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs index dccd0c453..81b8919c7 100644 --- a/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs +++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs @@ -62,21 +62,20 @@ namespace Artemis.Plugins.LayerBrushes.Noise public LayerProperty ScrollSpeedProperty { get; set; } public LayerProperty AnimationSpeedProperty { get; set; } - private void UpdateColorProperties() { - UnRegisterLayerProperty(MainColorProperty); - UnRegisterLayerProperty(SecondaryColorProperty); - UnRegisterLayerProperty(GradientColorProperty); if (GradientColorProperty != null) GradientColorProperty.Value.PropertyChanged -= CreateColorMap; if (ColorTypeProperty.Value == ColorMappingType.Simple) { + UnRegisterLayerProperty(GradientColorProperty); MainColorProperty = RegisterLayerProperty("Brush.MainColor", "Main color", "The main color of the noise", new SKColor(255, 0, 0)); SecondaryColorProperty = RegisterLayerProperty("Brush.SecondaryColor", "Secondary color", "The secondary color of the noise", new SKColor(0, 0, 255)); } else { + UnRegisterLayerProperty(MainColorProperty); + UnRegisterLayerProperty(SecondaryColorProperty); GradientColorProperty = RegisterLayerProperty("Brush.GradientColor", "Noise gradient map", "The gradient the noise will map it's value to", new ColorGradient()); if (!GradientColorProperty.Value.Stops.Any()) GradientColorProperty.Value.MakeFabulous();