diff --git a/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs b/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs index bd9fe7c7a..18c570c9a 100644 --- a/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs +++ b/src/Artemis.Core/Models/Profile/Colors/ColorGradient.cs @@ -51,6 +51,7 @@ public class ColorGradient : IList, IList, INotifyCollectionC { ColorGradientStop stop = new(colorGradientStop.Color, colorGradientStop.Position); stop.PropertyChanged += ItemOnPropertyChanged; + stop.ColorGradient = this; _stops.Add(stop); } } @@ -66,6 +67,7 @@ public class ColorGradient : IList, IList, INotifyCollectionC { ColorGradientStop stop = new(colorGradientStop.Color, colorGradientStop.Position); stop.PropertyChanged += ItemOnPropertyChanged; + stop.ColorGradient = this; _stops.Add(stop); } } @@ -465,6 +467,7 @@ public class ColorGradient : IList, IList, INotifyCollectionC public void Add(ColorGradientStop item) { _stops.Add(item); + item.ColorGradient = this; item.PropertyChanged += ItemOnPropertyChanged; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, _stops.IndexOf(item))); diff --git a/src/Artemis.Core/Models/Profile/Colors/ColorGradientStop.cs b/src/Artemis.Core/Models/Profile/Colors/ColorGradientStop.cs index 8ccddbf24..96af9f2b6 100644 --- a/src/Artemis.Core/Models/Profile/Colors/ColorGradientStop.cs +++ b/src/Artemis.Core/Models/Profile/Colors/ColorGradientStop.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using SkiaSharp; namespace Artemis.Core; @@ -35,9 +36,11 @@ public class ColorGradientStop : CorePropertyChanged public float Position { get => _position; - set => SetAndNotify(ref _position, value); + set => SetAndNotify(ref _position, GetUpdatedPosition(value)); } + internal ColorGradient? ColorGradient { get; set; } + #region Equality members /// @@ -64,5 +67,32 @@ public class ColorGradientStop : CorePropertyChanged return HashCode.Combine(_color, _position); } + /// + /// Gets the position of the given color stop in a safe manner that avoids overlap with other stops. + /// + /// The new position. + private float GetUpdatedPosition(float stopPosition) + { + if (ColorGradient == null) + return stopPosition; + // Find the first available spot going down + while (ColorGradient.Any(s => !ReferenceEquals(s, this) && Math.Abs(s.Position - stopPosition) < 0.001f)) + stopPosition -= 0.001f; + + // If we ran out of space, try going up + if (stopPosition < 0) + { + stopPosition = 0; + while (ColorGradient.Any(s => !ReferenceEquals(s, this) && Math.Abs(s.Position - stopPosition) < 0.001f)) + stopPosition += 0.001f; + } + + // If we ran out of space there too, movement isn't possible + if (stopPosition > 1) + stopPosition = Position; + + return stopPosition; + } + #endregion } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs b/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs new file mode 100644 index 000000000..3c73456a7 --- /dev/null +++ b/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs @@ -0,0 +1,63 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Interactivity; +using Avalonia.Xaml.Interactivity; +using FluentAvalonia.UI.Controls; + +namespace Artemis.UI.Shared.Behaviors; + +/// +/// Represents a behavior that can be used to make a numeric up down only update it's binding on focus loss. +/// +public class LostFocusNumericUpDownBindingBehavior : Behavior +{ + /// + /// Gets or sets the value of the binding. + /// + public static readonly StyledProperty ValueProperty = AvaloniaProperty.Register( + nameof(Value), defaultBindingMode: BindingMode.TwoWay); + + static LostFocusNumericUpDownBindingBehavior() + { + ValueProperty.Changed.Subscribe(e => ((LostFocusNumericUpDownBindingBehavior) e.Sender).OnBindingValueChanged()); + } + + /// + /// Gets or sets the value of the binding. + /// + public double Value + { + get => GetValue(ValueProperty); + set => SetValue(ValueProperty, value); + } + + /// + protected override void OnAttached() + { + if (AssociatedObject != null) + AssociatedObject.LostFocus += OnLostFocus; + base.OnAttached(); + } + + /// + protected override void OnDetaching() + { + if (AssociatedObject != null) + AssociatedObject.LostFocus -= OnLostFocus; + base.OnDetaching(); + } + + private void OnLostFocus(object? sender, RoutedEventArgs e) + { + if (AssociatedObject != null) + Value = AssociatedObject.Value; + } + + private void OnBindingValueChanged() + { + if (AssociatedObject != null) + AssociatedObject.Value = Value; + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml b/src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml index aa096987b..5d0a4e113 100644 --- a/src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml +++ b/src/Artemis.UI.Shared/Styles/Controls/GradientPicker.axaml @@ -4,7 +4,8 @@ xmlns:core="clr-namespace:Artemis.Core;assembly=Artemis.Core" xmlns:fluent="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters" - xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker"> + xmlns:gradientPicker="clr-namespace:Artemis.UI.Shared.Controls.GradientPicker" + xmlns:behaviors="clr-namespace:Artemis.UI.Shared.Behaviors"> @@ -198,7 +199,11 @@ - + + + + +