diff --git a/src/Artemis.Core/Plugins/Abstract/ViewModels/BrushConfigurationViewModel.cs b/src/Artemis.Core/Plugins/Abstract/ViewModels/BrushConfigurationViewModel.cs new file mode 100644 index 000000000..04d8748cc --- /dev/null +++ b/src/Artemis.Core/Plugins/Abstract/ViewModels/BrushConfigurationViewModel.cs @@ -0,0 +1,15 @@ +using Artemis.Core.Plugins.LayerBrush.Abstract; +using Stylet; + +namespace Artemis.Core.Plugins.Abstract.ViewModels +{ + public abstract class BrushConfigurationViewModel : Screen + { + protected BrushConfigurationViewModel(BaseLayerBrush layerBrush) + { + LayerBrush = layerBrush; + } + + public BaseLayerBrush LayerBrush { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Abstract/ViewModels/EffectConfigurationViewModel.cs b/src/Artemis.Core/Plugins/Abstract/ViewModels/EffectConfigurationViewModel.cs new file mode 100644 index 000000000..bce1850ba --- /dev/null +++ b/src/Artemis.Core/Plugins/Abstract/ViewModels/EffectConfigurationViewModel.cs @@ -0,0 +1,15 @@ +using Artemis.Core.Plugins.LayerEffect.Abstract; +using Stylet; + +namespace Artemis.Core.Plugins.Abstract.ViewModels +{ + public abstract class EffectConfigurationViewModel : Screen + { + protected EffectConfigurationViewModel(BaseLayerEffect layerEffect) + { + LayerEffect = layerEffect; + } + + public BaseLayerEffect LayerEffect { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/Abstract/ViewModels/PluginConfigurationViewModel.cs b/src/Artemis.Core/Plugins/Abstract/ViewModels/PluginConfigurationViewModel.cs index faa749601..56bc05dcd 100644 --- a/src/Artemis.Core/Plugins/Abstract/ViewModels/PluginConfigurationViewModel.cs +++ b/src/Artemis.Core/Plugins/Abstract/ViewModels/PluginConfigurationViewModel.cs @@ -9,6 +9,6 @@ namespace Artemis.Core.Plugins.Abstract.ViewModels Plugin = plugin; } - public Plugin Plugin { get; set; } + public Plugin Plugin { get; } } } \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerBrush/Abstract/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrush/Abstract/BaseLayerBrush.cs index d94355474..f34fb431d 100644 --- a/src/Artemis.Core/Plugins/LayerBrush/Abstract/BaseLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrush/Abstract/BaseLayerBrush.cs @@ -1,5 +1,6 @@ using System; using Artemis.Core.Models.Profile; +using Artemis.Core.Plugins.Abstract.ViewModels; using Artemis.Core.Plugins.Exceptions; using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Interfaces; @@ -70,6 +71,12 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract } } + /// + /// Gets or sets whether this plugin has a configuration view model. + /// If set to true, will be called when the plugin is configured from the UI. + /// + public bool HasConfigurationViewModel { get; protected set; } + public void Dispose() { DisableLayerBrush(); @@ -94,6 +101,16 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract /// public abstract void Update(double deltaTime); + /// + /// Called when the brush configuration window is opened from the UI. The UI will only attempt to open if + /// is set to True. + /// + /// + public virtual BrushConfigurationViewModel GetConfigurationViewModel() + { + return null; + } + // Not only is this needed to initialize properties on the layer brushes, it also prevents implementing anything // but LayerBrush and RgbNetLayerBrush outside the core internal abstract void Initialize(ILayerService layerService); diff --git a/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs index b7e8cad5a..c93a290cb 100644 --- a/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs +++ b/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs @@ -1,5 +1,6 @@ using System; using Artemis.Core.Models.Profile; +using Artemis.Core.Plugins.Abstract.ViewModels; using Artemis.Core.Plugins.Models; using Artemis.Core.Services.Interfaces; using SkiaSharp; @@ -96,6 +97,12 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract internal string PropertyRootPath => $"LayerEffect.{EntityId}.{GetType().Name}."; + /// + /// Gets or sets whether this plugin has a configuration view model. + /// If set to true, will be called when the plugin is configured from the UI. + /// + public bool HasConfigurationViewModel { get; protected set; } + public void Dispose() { DisableLayerEffect(); @@ -138,5 +145,16 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract // Not only is this needed to initialize properties on the layer effects, it also prevents implementing anything // but LayerEffect outside the core internal abstract void Initialize(ILayerService layerService); + + + /// + /// Called when the effect configuration window is opened from the UI. The UI will only attempt to open if + /// is set to True. + /// + /// + public virtual EffectConfigurationViewModel GetConfigurationViewModel() + { + return null; + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerBrushSettingsWindowView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerBrushSettingsWindowView.xaml new file mode 100644 index 000000000..f98ae0fb6 --- /dev/null +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerBrushSettingsWindowView.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerBrushSettingsWindowViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerBrushSettingsWindowViewModel.cs new file mode 100644 index 000000000..91f355feb --- /dev/null +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerBrushSettingsWindowViewModel.cs @@ -0,0 +1,14 @@ +using Artemis.Core.Plugins.Abstract.ViewModels; +using MaterialDesignThemes.Wpf; +using Stylet; + +namespace Artemis.UI.Screens.Module.ProfileEditor +{ + public class LayerBrushSettingsWindowViewModel : Conductor + { + public LayerBrushSettingsWindowViewModel(BrushConfigurationViewModel configurationViewModel) + { + ActiveItem = configurationViewModel; + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerEffectSettingsWindowView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerEffectSettingsWindowView.xaml new file mode 100644 index 000000000..64ebfe774 --- /dev/null +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerEffectSettingsWindowView.xaml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerEffectSettingsWindowViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerEffectSettingsWindowViewModel.cs new file mode 100644 index 000000000..ed0283dbb --- /dev/null +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerEffectSettingsWindowViewModel.cs @@ -0,0 +1,13 @@ +using Artemis.Core.Plugins.Abstract.ViewModels; +using Stylet; + +namespace Artemis.UI.Screens.Module.ProfileEditor +{ + public class LayerEffectSettingsWindowViewModel : Conductor + { + public LayerEffectSettingsWindowViewModel(EffectConfigurationViewModel configurationViewModel) + { + ActiveItem = configurationViewModel; + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml index 6deeeaa8f..55d53b651 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml @@ -67,9 +67,15 @@ - - - - - - Brush -  - - + + + + Brush -  + + + + + @@ -151,6 +177,15 @@ Command="{s:Action RenameEffect}"> + - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupViewModel.cs index 8aba6b8f6..f48ef27d3 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using Artemis.Core.Services.Interfaces; using Artemis.UI.Screens.Module.ProfileEditor.Dialogs; @@ -11,20 +12,52 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree public class TreePropertyGroupViewModel : PropertyChangedBase { private readonly IDialogService _dialogService; + private readonly IWindowManager _windowManager; private readonly ILayerService _layerService; private readonly IProfileEditorService _profileEditorService; public TreePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel, - IProfileEditorService profileEditorService, ILayerService layerService, IDialogService dialogService) + IProfileEditorService profileEditorService, ILayerService layerService, IDialogService dialogService, IWindowManager windowManager) { _profileEditorService = profileEditorService; _layerService = layerService; _dialogService = dialogService; + _windowManager = windowManager; LayerPropertyGroupViewModel = (LayerPropertyGroupViewModel) layerPropertyBaseViewModel; } public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; } + public async void OpenBrushSettings() + { + try + { + var configurationViewModel = LayerPropertyGroupViewModel.LayerPropertyGroup.LayerBrush.GetConfigurationViewModel(); + if (configurationViewModel != null) + _windowManager.ShowDialog(new LayerBrushSettingsWindowViewModel(configurationViewModel)); + } + catch (Exception e) + { + await _dialogService.ShowExceptionDialog("An exception occured while trying to show the brush's settings window", e); + throw; + } + } + + public async void OpenEffectSettings() + { + try + { + var configurationViewModel = LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.GetConfigurationViewModel(); + if (configurationViewModel != null) + _windowManager.ShowDialog(new LayerEffectSettingsWindowViewModel(configurationViewModel)); + } + catch (Exception e) + { + await _dialogService.ShowExceptionDialog("An exception occured while trying to show the effect's settings window", e); + throw; + } + } + public async void RenameEffect() { var result = await _dialogService.ShowDialogAt( diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs index dfd8b8571..bc5701ce4 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs @@ -68,7 +68,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins { var configurationViewModel = Plugin.GetConfigurationViewModel(); if (configurationViewModel != null) - _windowManager.ShowDialog(new PluginSettingsWindowViewModel(configurationViewModel)); + _windowManager.ShowDialog(new PluginSettingsWindowViewModel(configurationViewModel, Icon)); } catch (Exception e) { diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml index 52706e2ec..11a9251f2 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowView.xaml @@ -6,8 +6,9 @@ xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Plugins" xmlns:controls="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions" xmlns:s="https://github.com/canton7/Stylet" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" mc:Ignorable="d" - Title="{Binding Title}" + Title="Plugin configuration" Background="{DynamicResource MaterialDesignPaper}" FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto" UseLayoutRounding="True" @@ -17,7 +18,13 @@ d:DesignWidth="800" d:DataContext="{d:DesignInstance local:PluginSettingsWindowViewModel}" Icon="/Resources/Images/Logo/logo-512.png"> - + + + + + + + - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs index 1208db06d..1c5b9faa1 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsWindowViewModel.cs @@ -1,15 +1,17 @@ using Artemis.Core.Plugins.Abstract.ViewModels; +using MaterialDesignThemes.Wpf; using Stylet; namespace Artemis.UI.Screens.Settings.Tabs.Plugins { public class PluginSettingsWindowViewModel : Conductor { - public PluginSettingsWindowViewModel(PluginConfigurationViewModel configurationViewModel) + public PackIconKind Icon { get; } + + public PluginSettingsWindowViewModel(PluginConfigurationViewModel configurationViewModel, PackIconKind icon) { + Icon = icon; ActiveItem = configurationViewModel; } - - public string Title => "Plugin configuration - " + ActiveItem?.Plugin?.PluginInfo?.Name; } } \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs b/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs index 6828a813d..f20b5635a 100644 --- a/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs +++ b/src/Plugins/Artemis.Plugins.LayerBrushes.Noise/NoiseBrush.cs @@ -102,9 +102,7 @@ namespace Artemis.Plugins.LayerBrushes.Noise ); if (Properties.ColorType.BaseValue == ColorMappingType.Simple) - { paint.Color = Properties.SecondaryColor.CurrentValue; - } using var foregroundShader = SKShader.CreateBitmap(_bitmap, SKShaderTileMode.Clamp, SKShaderTileMode.Clamp, bitmapTransform); paint.Shader = foregroundShader; diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ColorMatrixEffect.cs b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ColorMatrixEffect.cs new file mode 100644 index 000000000..b6e237b3b --- /dev/null +++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ColorMatrixEffect.cs @@ -0,0 +1,37 @@ +using Artemis.Core.Plugins.Abstract.ViewModels; +using Artemis.Core.Plugins.LayerEffect.Abstract; +using Artemis.Plugins.LayerEffects.Filter.ViewModels; +using SkiaSharp; + +namespace Artemis.Plugins.LayerEffects.Filter +{ + public class ColorMatrixEffect : LayerEffect + { + public override void EnableLayerEffect() + { + HasConfigurationViewModel = true; + } + + public override EffectConfigurationViewModel GetConfigurationViewModel() + { + return new ColorMatrixConfigurationViewModel(this); + } + + public override void DisableLayerEffect() + { + } + + public override void Update(double deltaTime) + { + } + + public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint) + { + } + + public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint) + { + paint.ImageFilter = SKImageFilter.CreateColorFilter(SKColorFilter.CreateColorMatrix(Properties.ColorMatrix.CurrentValue), paint.ImageFilter); + } + } +} \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ColorMatrixEffectProperties.cs b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ColorMatrixEffectProperties.cs new file mode 100644 index 000000000..bedcfd5fa --- /dev/null +++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ColorMatrixEffectProperties.cs @@ -0,0 +1,29 @@ +using Artemis.Core.Models.Profile; +using Artemis.Core.Models.Profile.LayerProperties; +using Artemis.Core.Models.Profile.LayerProperties.Attributes; + +namespace Artemis.Plugins.LayerEffects.Filter +{ + public class ColorMatrixEffectProperties : LayerPropertyGroup + { + [PropertyDescription] + public LayerProperty ColorMatrix { get; set; } + + protected override void PopulateDefaults() + { + // Set a gray scale value as default + ColorMatrix.DefaultValue = new[] + { + 0.21f, 0.72f, 0.07f, 0, 0, + 0.21f, 0.72f, 0.07f, 0, 0, + 0.21f, 0.72f, 0.07f, 0, 0, + 0, 0, 0, 1, 0 + }; + } + + protected override void OnPropertiesInitialized() + { + ColorMatrix.IsHidden = true; + } + } +} \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProvider.cs b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProvider.cs index f1973786d..050b4fcb5 100644 --- a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProvider.cs +++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/FilterEffectProvider.cs @@ -15,6 +15,7 @@ namespace Artemis.Plugins.LayerEffects.Filter AddLayerEffectDescriptor("Erode", "A layer effect providing an erode filter effect", "EyeMinus"); AddLayerEffectDescriptor("Glow", "A layer effect providing a glow filter effect", "BoxShadow"); AddLayerEffectDescriptor("Gray-scale", "A layer effect providing a gray-scale filter effect", "InvertColors"); + AddLayerEffectDescriptor("Color matrix", "A layer effect allowing you to apply a custom color matrix", "Matrix"); } public override void DisablePlugin() diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ViewModels/ColorMatrixConfigurationViewModel.cs b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ViewModels/ColorMatrixConfigurationViewModel.cs new file mode 100644 index 000000000..2661c07a8 --- /dev/null +++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/ViewModels/ColorMatrixConfigurationViewModel.cs @@ -0,0 +1,23 @@ +using System.Diagnostics; +using Artemis.Core.Plugins.Abstract.ViewModels; + +namespace Artemis.Plugins.LayerEffects.Filter.ViewModels +{ + public class ColorMatrixConfigurationViewModel : EffectConfigurationViewModel + { + public ColorMatrixConfigurationViewModel(ColorMatrixEffect layerEffect) : base(layerEffect) + { + Properties = layerEffect.Properties; + } + + public ColorMatrixEffectProperties Properties { get; set; } + + public void OpenGuide() + { + Process.Start(new ProcessStartInfo("cmd", "/c start https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/effects/color-filters") + { + CreateNoWindow = true + }); + } + } +} \ No newline at end of file diff --git a/src/Plugins/Artemis.Plugins.LayerEffects.Filter/Views/ColorMatrixConfigurationView.xaml b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/Views/ColorMatrixConfigurationView.xaml new file mode 100644 index 000000000..87572380d --- /dev/null +++ b/src/Plugins/Artemis.Plugins.LayerEffects.Filter/Views/ColorMatrixConfigurationView.xaml @@ -0,0 +1,65 @@ + + + + Below you can define the color matrix to be applied to the folder/layer. + Please note this is an advanced effect mainly included for the sake of completion. + + + If you are still not deterred, + + click here + + for a full explanation of color transforms in SkiaSharp, the rendering library Artemis uses. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file