From 3d38461bddaf395f286ede54661fb1e31773cc30 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 5 Apr 2021 22:05:45 +0200 Subject: [PATCH] Brushes - Added brush presets ColorGradient - Refactored so it implements IList --- .../Properties/ColorGradientLayerProperty.cs | 18 +- .../Models/Profile/Colors/ColorGradient.cs | 178 ++++- src/Artemis.Core/Models/Profile/Layer.cs | 3 + .../Profile/LayerProperties/ILayerProperty.cs | 5 + .../Plugins/LayerBrushes/ILayerBrushPreset.cs | 28 + .../LayerBrushes/Internal/BaseLayerBrush.cs | 12 + .../Internal/PropertiesLayerBrush.cs | 2 + .../Controls/GradientPicker.xaml | 2 +- .../ColorGradientToGradientStopsConverter.cs | 12 +- .../GradientEditor/ColorStopViewModel.cs | 11 +- .../GradientEditor/GradientEditorView.xaml | 2 +- .../GradientEditor/GradientEditorViewModel.cs | 44 +- .../Services/ProfileEditorService.cs | 28 +- .../BrushPropertyInputViewModel.cs | 17 +- .../ColorGradientPropertyInputView.xaml | 1 + .../Dialogs/LayerBrushPresetView.xaml | 42 ++ .../Dialogs/LayerBrushPresetViewModel.cs | 40 + .../LayerProperties/LayerPropertiesView.xaml | 696 +++++++++--------- 18 files changed, 722 insertions(+), 419 deletions(-) create mode 100644 src/Artemis.Core/Plugins/LayerBrushes/ILayerBrushPreset.cs create mode 100644 src/Artemis.UI/Screens/ProfileEditor/Dialogs/LayerBrushPresetView.xaml create mode 100644 src/Artemis.UI/Screens/ProfileEditor/Dialogs/LayerBrushPresetViewModel.cs diff --git a/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs b/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs index 387c2d9ef..e811a4e0f 100644 --- a/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs +++ b/src/Artemis.Core/DefaultTypes/Properties/ColorGradientLayerProperty.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.Specialized; +using System.ComponentModel; using SkiaSharp; namespace Artemis.Core @@ -23,17 +24,16 @@ namespace Artemis.Core if (CurrentValue == null) return; - for (int index = 0; index < CurrentValue.Stops.Count; index++) + for (int index = 0; index < CurrentValue.Count; index++) { int stopIndex = index; void Setter(SKColor value) { - CurrentValue.Stops[stopIndex].Color = value; - CurrentValue.OnColorValuesUpdated(); + CurrentValue[stopIndex].Color = value; } - RegisterDataBindingProperty(() => CurrentValue.Stops[stopIndex].Color, Setter, new ColorStopDataBindingConverter(), $"Color #{stopIndex + 1}"); + RegisterDataBindingProperty(() => CurrentValue[stopIndex].Color, Setter, new ColorStopDataBindingConverter(), $"Color #{stopIndex + 1}"); } } @@ -61,17 +61,17 @@ namespace Artemis.Core if (_subscribedGradient != BaseValue) { if (_subscribedGradient != null) - _subscribedGradient.PropertyChanged -= SubscribedGradientOnPropertyChanged; + _subscribedGradient.CollectionChanged -= SubscribedGradientOnPropertyChanged; _subscribedGradient = BaseValue; - _subscribedGradient.PropertyChanged += SubscribedGradientOnPropertyChanged; + _subscribedGradient.CollectionChanged += SubscribedGradientOnPropertyChanged; } CreateDataBindingRegistrations(); } - private void SubscribedGradientOnPropertyChanged(object? sender, PropertyChangedEventArgs e) + private void SubscribedGradientOnPropertyChanged(object? sender, NotifyCollectionChangedEventArgs args) { - if (CurrentValue.Stops.Count != GetAllDataBindingRegistrations().Count) + if (CurrentValue.Count != GetAllDataBindingRegistrations().Count) CreateDataBindingRegistrations(); } diff --git a/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs b/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs index 4f630fcda..c621eb5c7 100644 --- a/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs +++ b/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs @@ -1,5 +1,8 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; using System.Linq; using SkiaSharp; @@ -8,7 +11,7 @@ namespace Artemis.Core /// /// A gradient containing a list of s /// - public class ColorGradient : CorePropertyChanged + public class ColorGradient : IList, INotifyCollectionChanged { private static readonly SKColor[] FastLedRainbow = { @@ -23,19 +26,16 @@ namespace Artemis.Core new(0xFFFF0000) // and back to Red }; + private readonly List _stops; + /// /// Creates a new instance of the class /// public ColorGradient() { - Stops = new List(); + _stops = new List(); } - /// - /// Gets a list of all the s in the gradient - /// - public List Stops { get; } - /// /// Gets all the colors in the color gradient /// @@ -49,13 +49,16 @@ namespace Artemis.Core { List result = new(); if (timesToRepeat == 0) - result = Stops.Select(c => c.Color).ToList(); + { + result = this.Select(c => c.Color).ToList(); + } else { - List colors = Stops.Select(c => c.Color).ToList(); + List colors = this.Select(c => c.Color).ToList(); for (int i = 0; i <= timesToRepeat; i++) result.AddRange(colors); } + if (seamless && !IsSeamless()) result.Add(result[0]); @@ -77,11 +80,13 @@ namespace Artemis.Core { List result = new(); if (timesToRepeat == 0) - result = Stops.Select(c => c.Position).ToList(); + { + result = this.Select(c => c.Position).ToList(); + } else { // Create stops and a list of divided stops - List stops = Stops.Select(c => c.Position / (timesToRepeat + 1)).ToList(); + List stops = this.Select(c => c.Position / (timesToRepeat + 1)).ToList(); // For each repeat cycle, add the base stops to the end result for (int i = 0; i <= timesToRepeat; i++) @@ -104,25 +109,16 @@ namespace Artemis.Core return result.ToArray(); } - /// - /// Triggers a property changed event of the collection - /// - public void OnColorValuesUpdated() - { - Stops.Sort((a, b) => a.Position.CompareTo(b.Position)); - OnPropertyChanged(nameof(Stops)); - } - /// /// Gets a color at any position between 0.0 and 1.0 using interpolation /// /// A position between 0.0 and 1.0 public SKColor GetColor(float position) { - if (!Stops.Any()) + if (!this.Any()) return SKColor.Empty; - ColorGradientStop[] stops = Stops.ToArray(); + ColorGradientStop[] stops = this.ToArray(); if (position <= 0) return stops[0].Color; if (position >= 1) return stops[^1].Color; ColorGradientStop left = stops[0]; @@ -160,7 +156,7 @@ namespace Artemis.Core { SKColor skColor = FastLedRainbow[index]; float position = 1f / (FastLedRainbow.Length - 1f) * index; - gradient.Stops.Add(new ColorGradientStop(skColor, position)); + gradient.Add(new ColorGradientStop(skColor, position)); } return gradient; @@ -172,7 +168,141 @@ namespace Artemis.Core /// if the gradient is seamless; otherwise public bool IsSeamless() { - return Stops.Count == 0 || Stops.First().Color.Equals(Stops.Last().Color); + return Count == 0 || this.First().Color.Equals(this.Last().Color); } + + internal void Sort() + { + _stops.Sort((a, b) => a.Position.CompareTo(b.Position)); + } + + private void ItemOnPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + Sort(); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + + #region Implementation of IEnumerable + + /// + public IEnumerator GetEnumerator() + { + return _stops.GetEnumerator(); + } + + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + #region Implementation of ICollection + + /// + public void Add(ColorGradientStop item) + { + _stops.Add(item); + item.PropertyChanged += ItemOnPropertyChanged; + Sort(); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, _stops.IndexOf(item))); + } + + + /// + public void Clear() + { + foreach (ColorGradientStop item in _stops) + item.PropertyChanged -= ItemOnPropertyChanged; + _stops.Clear(); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + + /// + public bool Contains(ColorGradientStop item) + { + return _stops.Contains(item); + } + + /// + public void CopyTo(ColorGradientStop[] array, int arrayIndex) + { + _stops.CopyTo(array, arrayIndex); + } + + /// + public bool Remove(ColorGradientStop item) + { + item.PropertyChanged -= ItemOnPropertyChanged; + int index = _stops.IndexOf(item); + bool removed = _stops.Remove(item); + if (removed) + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, index)); + + return removed; + } + + /// + public int Count => _stops.Count; + + /// + public bool IsReadOnly => false; + + #endregion + + #region Implementation of IList + + /// + public int IndexOf(ColorGradientStop item) + { + return _stops.IndexOf(item); + } + + /// + public void Insert(int index, ColorGradientStop item) + { + _stops.Insert(index, item); + item.PropertyChanged += ItemOnPropertyChanged; + Sort(); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, _stops.IndexOf(item))); + } + + /// + public void RemoveAt(int index) + { + _stops[index].PropertyChanged -= ItemOnPropertyChanged; + _stops.RemoveAt(index); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, index)); + } + + /// + public ColorGradientStop this[int index] + { + get => _stops[index]; + set + { + ColorGradientStop? oldValue = _stops[index]; + oldValue.PropertyChanged -= ItemOnPropertyChanged; + _stops[index] = value; + _stops[index].PropertyChanged += ItemOnPropertyChanged; + Sort(); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldValue)); + } + } + + #endregion + + #region Implementation of INotifyCollectionChanged + + /// + public event NotifyCollectionChangedEventHandler? CollectionChanged; + + private void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + CollectionChanged?.Invoke(this, e); + } + + #endregion } } \ 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 47a08ab8a..5e544e187 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -297,6 +297,9 @@ namespace Artemis.Core private void ApplyTimeline(Timeline timeline) { + if (timeline.Delta == TimeSpan.Zero) + return; + General.Update(timeline); Transform.Update(timeline); if (LayerBrush != null) diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs index c42b1f74c..2b4202cb9 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/ILayerProperty.cs @@ -33,6 +33,11 @@ namespace Artemis.Core /// Type PropertyType { get; } + /// + /// Indicates whether the BaseValue was loaded from storage, useful to check whether a default value must be applied + /// + bool IsLoadedFromStorage { get; } + /// /// Initializes the layer property /// diff --git a/src/Artemis.Core/Plugins/LayerBrushes/ILayerBrushPreset.cs b/src/Artemis.Core/Plugins/LayerBrushes/ILayerBrushPreset.cs new file mode 100644 index 000000000..72fa2aa40 --- /dev/null +++ b/src/Artemis.Core/Plugins/LayerBrushes/ILayerBrushPreset.cs @@ -0,0 +1,28 @@ +namespace Artemis.Core.LayerBrushes +{ + /// + /// Represents a brush preset for a brush. + /// + public interface ILayerBrushPreset + { + /// + /// Gets the name of the preset + /// + string Name { get; } + + /// + /// Gets the description of the preset + /// + string Description { get; } + + /// + /// Gets the icon of the preset + /// + string Icon { get; } + + /// + /// Applies the preset to the layer brush + /// + void Apply(); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs index c452384e3..2e1712250 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using SkiaSharp; namespace Artemis.Core.LayerBrushes @@ -70,6 +72,16 @@ namespace Artemis.Core.LayerBrushes /// public virtual LayerPropertyGroup? BaseProperties => null; + /// + /// Gets a list of presets available to this layer brush + /// + public virtual List? Presets => null; + + /// + /// Gets the default preset used for new instances of this layer brush + /// + public virtual ILayerBrushPreset? DefaultPreset => Presets?.FirstOrDefault(); + /// /// Gets or sets whether the brush supports transformations /// Note: RGB.NET brushes can never be transformed and setting this to true will throw an exception diff --git a/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs index 5b12849b8..9184e1c6b 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/Internal/PropertiesLayerBrush.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; namespace Artemis.Core.LayerBrushes { diff --git a/src/Artemis.UI.Shared/Controls/GradientPicker.xaml b/src/Artemis.UI.Shared/Controls/GradientPicker.xaml index e9f083456..be9ac72d7 100644 --- a/src/Artemis.UI.Shared/Controls/GradientPicker.xaml +++ b/src/Artemis.UI.Shared/Controls/GradientPicker.xaml @@ -38,7 +38,7 @@ diff --git a/src/Artemis.UI.Shared/Converters/ColorGradientToGradientStopsConverter.cs b/src/Artemis.UI.Shared/Converters/ColorGradientToGradientStopsConverter.cs index ad4138311..2a1c9de0a 100644 --- a/src/Artemis.UI.Shared/Converters/ColorGradientToGradientStopsConverter.cs +++ b/src/Artemis.UI.Shared/Converters/ColorGradientToGradientStopsConverter.cs @@ -14,18 +14,18 @@ namespace Artemis.UI.Shared /// Converts into a /// . /// - [ValueConversion(typeof(List), typeof(GradientStopCollection))] + [ValueConversion(typeof(ColorGradient), typeof(GradientStopCollection))] public class ColorGradientToGradientStopsConverter : IValueConverter { /// public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - List colorGradients = (List) value; + ColorGradient? colorGradient = value as ColorGradient; GradientStopCollection collection = new(); - if (colorGradients == null) + if (colorGradient == null) return collection; - foreach (ColorGradientStop c in colorGradients.OrderBy(s => s.Position)) + foreach (ColorGradientStop c in colorGradient.OrderBy(s => s.Position)) collection.Add(new GradientStop(Color.FromArgb(c.Color.Alpha, c.Color.Red, c.Color.Green, c.Color.Blue), c.Position)); return collection; } @@ -33,8 +33,8 @@ namespace Artemis.UI.Shared /// public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - GradientStopCollection collection = (GradientStopCollection) value; - List colorGradients = new(); + GradientStopCollection? collection = value as GradientStopCollection; + ColorGradient colorGradients = new(); if (collection == null) return colorGradients; diff --git a/src/Artemis.UI.Shared/Screens/GradientEditor/ColorStopViewModel.cs b/src/Artemis.UI.Shared/Screens/GradientEditor/ColorStopViewModel.cs index 7d93d868a..7629a9899 100644 --- a/src/Artemis.UI.Shared/Screens/GradientEditor/ColorStopViewModel.cs +++ b/src/Artemis.UI.Shared/Screens/GradientEditor/ColorStopViewModel.cs @@ -20,7 +20,6 @@ namespace Artemis.UI.Shared.Screens.GradientEditor { _gradientEditorViewModel = gradientEditorViewModel; ColorStop = colorStop; - ColorStop.PropertyChanged += ColorStopOnPropertyChanged; } public ColorGradientStop ColorStop { get; } @@ -58,12 +57,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor get => _willRemoveColorStop; set => SetAndNotify(ref _willRemoveColorStop, value); } - - private void ColorStopOnPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - _gradientEditorViewModel.ColorGradient.OnColorValuesUpdated(); - } - + #region Movement public void StopMouseDown(object sender, MouseButtonEventArgs e) @@ -102,7 +96,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor double minValue = 0.0; double maxValue = _gradientEditorViewModel.PreviewWidth; - List stops = _gradientEditorViewModel.ColorGradient.Stops.OrderBy(s => s.Position).ToList(); + List stops = _gradientEditorViewModel.ColorGradient.ToList(); ColorGradientStop? previous = stops.IndexOf(ColorStop) >= 1 ? stops[stops.IndexOf(ColorStop) - 1] : null; ColorGradientStop? next = stops.IndexOf(ColorStop) + 1 < stops.Count ? stops[stops.IndexOf(ColorStop) + 1] : null; if (previous != null) @@ -111,7 +105,6 @@ namespace Artemis.UI.Shared.Screens.GradientEditor maxValue = next.Position * _gradientEditorViewModel.PreviewWidth; Offset = Math.Max(minValue, Math.Min(maxValue, position.X)); - _gradientEditorViewModel.ColorGradient.OnColorValuesUpdated(); } #endregion diff --git a/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorView.xaml b/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorView.xaml index 49af71b72..64e084204 100644 --- a/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorView.xaml +++ b/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorView.xaml @@ -66,7 +66,7 @@ diff --git a/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorViewModel.cs b/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorViewModel.cs index f53a099af..497d81963 100644 --- a/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorViewModel.cs +++ b/src/Artemis.UI.Shared/Screens/GradientEditor/GradientEditorViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.Specialized; using System.ComponentModel; using System.Linq; using System.Windows; @@ -6,6 +7,7 @@ using System.Windows.Controls; using System.Windows.Input; using Artemis.Core; using Artemis.UI.Shared.Services; +using MaterialDesignThemes.Wpf; using Stylet; namespace Artemis.UI.Shared.Screens.GradientEditor @@ -21,12 +23,24 @@ namespace Artemis.UI.Shared.Screens.GradientEditor ColorGradient = colorGradient; ColorStopViewModels = new BindableCollection(); - _originalStops = ColorGradient.Stops.Select(s => new ColorGradientStop(s.Color, s.Position)).ToList(); + _originalStops = ColorGradient.Select(s => new ColorGradientStop(s.Color, s.Position)).ToList(); PropertyChanged += UpdateColorStopViewModels; + ColorGradient.CollectionChanged += ColorGradientOnCollectionChanged; } - public BindableCollection ColorStopViewModels { get; set; } + #region Overrides of DialogViewModelBase + + /// + public override void OnDialogClosed(object sender, DialogClosingEventArgs e) + { + ColorGradient.CollectionChanged -= ColorGradientOnCollectionChanged; + base.OnDialogClosed(sender, e); + } + + #endregion + + public BindableCollection ColorStopViewModels { get; } public ColorStopViewModel? SelectedColorStopViewModel { @@ -48,15 +62,19 @@ namespace Artemis.UI.Shared.Screens.GradientEditor set => SetAndNotify(ref _previewWidth, value); } + public ColorGradient Stops + { + get => ColorGradient; + } + public void AddColorStop(object sender, MouseEventArgs e) { Canvas? child = VisualTreeUtilities.FindChild((DependencyObject) sender, null); float position = (float) (e.GetPosition(child).X / PreviewWidth); ColorGradientStop stop = new(ColorGradient.GetColor(position), position); - ColorGradient.Stops.Add(stop); - ColorGradient.OnColorValuesUpdated(); + ColorGradient.Add(stop); - int index = ColorGradient.Stops.OrderBy(s => s.Position).ToList().IndexOf(stop); + int index = ColorGradient.IndexOf(stop); ColorStopViewModel viewModel = new(this, stop); ColorStopViewModels.Insert(index, viewModel); @@ -69,8 +87,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor return; ColorStopViewModels.Remove(colorStopViewModel); - ColorGradient.Stops.Remove(colorStopViewModel.ColorStop); - ColorGradient.OnColorValuesUpdated(); + ColorGradient.Remove(colorStopViewModel.ColorStop); SelectColorStop(null); } @@ -97,9 +114,9 @@ namespace Artemis.UI.Shared.Screens.GradientEditor public override void Cancel() { // Restore the saved state - ColorGradient.Stops.Clear(); - ColorGradient.Stops.AddRange(_originalStops); - ColorGradient.OnColorValuesUpdated(); + ColorGradient.Clear(); + foreach (ColorGradientStop colorGradientStop in _originalStops) + ColorGradient.Add(colorGradientStop); base.Cancel(); } @@ -107,8 +124,13 @@ namespace Artemis.UI.Shared.Screens.GradientEditor private void UpdateColorStopViewModels(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName != nameof(PreviewWidth)) return; - foreach (ColorGradientStop colorStop in ColorGradient.Stops.OrderBy(s => s.Position)) + foreach (ColorGradientStop colorStop in ColorGradient) ColorStopViewModels.Add(new ColorStopViewModel(this, colorStop)); } + + private void ColorGradientOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + NotifyOfPropertyChange(nameof(ColorGradient)); + } } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs index 79d71359b..fe72e1392 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Windows; +using System.Windows.Controls.Primitives; using Artemis.Core; using Artemis.Core.Modules; using Artemis.Core.Services; @@ -86,7 +87,7 @@ namespace Artemis.UI.Shared.Services { if (_currentTime.Equals(value)) return; _currentTime = value; - UpdateProfilePreview(); + Tick(); OnCurrentTimeChanged(); } } @@ -180,16 +181,9 @@ namespace Artemis.UI.Shared.Services public void UpdateProfilePreview() { - if (SelectedProfile == null) + if (Playing) return; - - // Stick to the main segment for any element that is not currently selected - foreach (Folder folder in SelectedProfile.GetAllFolders()) - folder.Timeline.Override(CurrentTime, folder.Timeline.PlayMode == TimelinePlayMode.Repeat); - foreach (Layer layer in SelectedProfile.GetAllLayers()) - layer.Timeline.Override(CurrentTime, (layer != SelectedProfileElement || layer.Timeline.Length < CurrentTime) && layer.Timeline.PlayMode == TimelinePlayMode.Repeat); - - _coreService.FrameRendered += CoreServiceOnFrameRendered; + Tick(); } public bool UndoUpdateProfile() @@ -357,6 +351,20 @@ namespace Artemis.UI.Shared.Services .ToList(); } + private void Tick() + { + if (SelectedProfile == null) + return; + + // Stick to the main segment for any element that is not currently selected + foreach (Folder folder in SelectedProfile.GetAllFolders()) + folder.Timeline.Override(CurrentTime, folder.Timeline.PlayMode == TimelinePlayMode.Repeat); + foreach (Layer layer in SelectedProfile.GetAllLayers()) + layer.Timeline.Override(CurrentTime, (layer != SelectedProfileElement || layer.Timeline.Length < CurrentTime) && layer.Timeline.PlayMode == TimelinePlayMode.Repeat); + + _coreService.FrameRendered += CoreServiceOnFrameRendered; + } + #region Copy/paste public ProfileElement? DuplicateProfileElement(ProfileElement profileElement) diff --git a/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs b/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs index 20409eb1c..c356cfc60 100644 --- a/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs +++ b/src/Artemis.UI/DefaultTypes/PropertyInput/BrushPropertyInputViewModel.cs @@ -1,8 +1,10 @@ using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.LayerBrushes; using Artemis.Core.Services; +using Artemis.UI.Screens.ProfileEditor.Dialogs; using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using Stylet; @@ -12,12 +14,15 @@ namespace Artemis.UI.DefaultTypes.PropertyInput public class BrushPropertyInputViewModel : PropertyInputViewModel { private readonly IPluginManagementService _pluginManagementService; + private readonly IDialogService _dialogService; private BindableCollection _descriptors; - public BrushPropertyInputViewModel(LayerProperty layerProperty, IProfileEditorService profileEditorService, IPluginManagementService pluginManagementService) + public BrushPropertyInputViewModel(LayerProperty layerProperty, IProfileEditorService profileEditorService, IPluginManagementService pluginManagementService, + IDialogService dialogService) : base(layerProperty, profileEditorService) { _pluginManagementService = pluginManagementService; + _dialogService = dialogService; UpdateEnumValues(); } @@ -43,7 +48,17 @@ namespace Artemis.UI.DefaultTypes.PropertyInput protected override void OnInputValueApplied() { if (LayerProperty.ProfileElement is Layer layer) + { layer.ChangeLayerBrush(SelectedDescriptor); + if (layer.LayerBrush?.Presets != null && layer.LayerBrush.Presets.Any()) + { + Execute.PostToUIThread(async () => + { + await Task.Delay(400); + _dialogService.ShowDialogAt("LayerProperties", new Dictionary {{"layerBrush", layer.LayerBrush}}); + }); + } + } } private void SetBrushByDescriptor(LayerBrushDescriptor value) diff --git a/src/Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.xaml b/src/Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.xaml index ef17ba34e..ea3f4a60f 100644 --- a/src/Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.xaml +++ b/src/Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:s="https://github.com/canton7/Stylet" xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" + xmlns:propertyInput="clr-namespace:Artemis.UI.DefaultTypes.PropertyInput" mc:Ignorable="d" d:DesignHeight="25" d:DesignWidth="800" d:DataContext="{d:DesignInstance propertyInput:ColorGradientPropertyInputViewModel}"> diff --git a/src/Artemis.UI/Screens/ProfileEditor/Dialogs/LayerBrushPresetView.xaml b/src/Artemis.UI/Screens/ProfileEditor/Dialogs/LayerBrushPresetView.xaml new file mode 100644 index 000000000..6958ab076 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Dialogs/LayerBrushPresetView.xaml @@ -0,0 +1,42 @@ + + + + Select a brush preset + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/Dialogs/LayerBrushPresetViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Dialogs/LayerBrushPresetViewModel.cs new file mode 100644 index 000000000..600dc2e42 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/Dialogs/LayerBrushPresetViewModel.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using Artemis.Core.LayerBrushes; +using Artemis.UI.Shared.Services; +using Stylet; + +namespace Artemis.UI.Screens.ProfileEditor.Dialogs +{ + public class LayerBrushPresetViewModel : DialogViewModelBase + { + private ILayerBrushPreset _selectedPreset; + + public LayerBrushPresetViewModel(BaseLayerBrush layerBrush) + { + Presets = new BindableCollection(); + Presets.AddRange(layerBrush.Presets); + } + + public BindableCollection Presets { get; } + + public ILayerBrushPreset SelectedPreset + { + get => _selectedPreset; + set + { + SetAndNotify(ref _selectedPreset, value); + SelectPreset(value); + } + } + + public void SelectPreset(ILayerBrushPreset preset) + { + preset.Apply(); + Execute.OnUIThreadAsync(async () => + { + await Task.Delay(250); + Session?.Close(true); + }); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesView.xaml b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesView.xaml index 5f640610f..a6f1a5dd0 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesView.xaml @@ -66,210 +66,188 @@ - - - - - - - - - - - - - + + - + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + Don't repeat the timeline + + + This setting only applies to the editor and affect the repeat mode during normal profile playback + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - + HorizontalAlignment="Right" + Margin="10 5" + Minimum="31" + Maximum="350" + TickFrequency="1" + IsSnapToTickEnabled="True" + AutoToolTipPlacement="TopLeft" + Value="{Binding ProfileEditorService.PixelsPerSecond}" + Width="319" /> + + - - - - - - - - - - - - - - - + \ No newline at end of file