diff --git a/RGB.NET.Brushes/Gradients/LinearGradient.cs b/RGB.NET.Brushes/Gradients/LinearGradient.cs index 8732262..c8f9227 100644 --- a/RGB.NET.Brushes/Gradients/LinearGradient.cs +++ b/RGB.NET.Brushes/Gradients/LinearGradient.cs @@ -1,6 +1,7 @@ // ReSharper disable UnusedMember.Global using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using RGB.NET.Core; @@ -12,6 +13,13 @@ namespace RGB.NET.Brushes.Gradients /// public class LinearGradient : AbstractGradient { + #region Properties & Fields + + private bool _isOrderedGradientListDirty = true; + private LinkedList _orderedGradientStops; + + #endregion + #region Constructors /// @@ -19,7 +27,9 @@ namespace RGB.NET.Brushes.Gradients /// Initializes a new instance of the class. /// public LinearGradient() - { } + { + Initialize(); + } /// /// @@ -28,7 +38,9 @@ namespace RGB.NET.Brushes.Gradients /// The stops with which the gradient should be initialized. public LinearGradient(params GradientStop[] gradientStops) : base(gradientStops) - { } + { + Initialize(); + } /// /// @@ -38,12 +50,33 @@ namespace RGB.NET.Brushes.Gradients /// The stops with which the gradient should be initialized. public LinearGradient(bool wrapGradient, params GradientStop[] gradientStops) : base(wrapGradient, gradientStops) - { } + { + Initialize(); + } #endregion #region Methods + private void Initialize() + { + void OnGradientStopOnPropertyChanged(object sender, PropertyChangedEventArgs args) => _isOrderedGradientListDirty = true; + + foreach (GradientStop gradientStop in GradientStops) + gradientStop.PropertyChanged += OnGradientStopOnPropertyChanged; + + GradientStops.CollectionChanged += (sender, args) => + { + if (args.OldItems != null) + foreach (GradientStop gradientStop in args.OldItems) + gradientStop.PropertyChanged -= OnGradientStopOnPropertyChanged; + + if (args.NewItems != null) + foreach (GradientStop gradientStop in args.NewItems) + gradientStop.PropertyChanged += OnGradientStopOnPropertyChanged; + }; + } + /// /// /// Gets the linear interpolated at the given offset. @@ -55,7 +88,10 @@ namespace RGB.NET.Brushes.Gradients if (GradientStops.Count == 0) return Color.Transparent; if (GradientStops.Count == 1) return GradientStops[0].Color; - (GradientStop gsBefore, GradientStop gsAfter) = GetEnclosingGradientStops(offset, GradientStops, WrapGradient); + if (_isOrderedGradientListDirty) + _orderedGradientStops = new LinkedList(GradientStops.OrderBy(x => x.Offset)); + + (GradientStop gsBefore, GradientStop gsAfter) = GetEnclosingGradientStops(offset, _orderedGradientStops, WrapGradient); double blendFactor = 0; if (!gsBefore.Offset.Equals(gsAfter.Offset)) @@ -73,12 +109,12 @@ namespace RGB.NET.Brushes.Gradients /// Get the two s encapsulating the given offset. /// /// The reference offset. - /// The to choose from. + /// The ordered list of to choose from. /// Bool indicating if the gradient should be wrapped or not. /// - protected virtual (GradientStop gsBefore, GradientStop gsAfter) GetEnclosingGradientStops(double offset, IEnumerable stops, bool wrap) + protected virtual (GradientStop gsBefore, GradientStop gsAfter) GetEnclosingGradientStops(double offset, LinkedList orderedStops, bool wrap) { - LinkedList orderedStops = new LinkedList(stops.OrderBy(x => x.Offset)); + LinkedList gradientStops = new LinkedList(orderedStops); if (wrap) { @@ -86,20 +122,20 @@ namespace RGB.NET.Brushes.Gradients do { - gsBefore = orderedStops.LastOrDefault(n => n.Offset <= offset); + gsBefore = gradientStops.LastOrDefault(n => n.Offset <= offset); if (gsBefore == null) { - GradientStop lastStop = orderedStops.Last.Value; - orderedStops.AddFirst(new GradientStop(lastStop.Offset - 1, lastStop.Color)); - orderedStops.RemoveLast(); + GradientStop lastStop = gradientStops.Last.Value; + gradientStops.AddFirst(new GradientStop(lastStop.Offset - 1, lastStop.Color)); + gradientStops.RemoveLast(); } - gsAfter = orderedStops.FirstOrDefault(n => n.Offset >= offset); + gsAfter = gradientStops.FirstOrDefault(n => n.Offset >= offset); if (gsAfter == null) { - GradientStop firstStop = orderedStops.First.Value; - orderedStops.AddLast(new GradientStop(firstStop.Offset + 1, firstStop.Color)); - orderedStops.RemoveFirst(); + GradientStop firstStop = gradientStops.First.Value; + gradientStops.AddLast(new GradientStop(firstStop.Offset + 1, firstStop.Color)); + gradientStops.RemoveFirst(); } } while ((gsBefore == null) || (gsAfter == null)); @@ -108,7 +144,7 @@ namespace RGB.NET.Brushes.Gradients } offset = ClipOffset(offset); - return (orderedStops.Last(n => n.Offset <= offset), orderedStops.First(n => n.Offset >= offset)); + return (gradientStops.Last(n => n.Offset <= offset), gradientStops.First(n => n.Offset >= offset)); } #endregion