diff --git a/samples/ControlCatalog/Pages/SliderPage.xaml b/samples/ControlCatalog/Pages/SliderPage.xaml index c6f5521e60..ea31ed0050 100644 --- a/samples/ControlCatalog/Pages/SliderPage.xaml +++ b/samples/ControlCatalog/Pages/SliderPage.xaml @@ -6,11 +6,22 @@ A control that lets the user select from a range of values by moving a Thumb control along a Track. - + + + + TickPlacementProperty = AvaloniaProperty.Register(nameof(TickPlacement), 0d); + /// + /// Defines the property. + /// + public static readonly StyledProperty> TicksProperty = + TickBar.TicksProperty.AddOwner(); + // Slider required parts private bool _isDragging = false; private Track _track; @@ -83,7 +90,8 @@ namespace Avalonia.Controls PressedMixin.Attach(); OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal); Thumb.DragStartedEvent.AddClassHandler((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble); - Thumb.DragCompletedEvent.AddClassHandler((x, e) => x.OnThumbDragCompleted(e), RoutingStrategies.Bubble); + Thumb.DragCompletedEvent.AddClassHandler((x, e) => x.OnThumbDragCompleted(e), + RoutingStrategies.Bubble); } /// @@ -94,6 +102,15 @@ namespace Avalonia.Controls UpdatePseudoClasses(Orientation); } + /// + /// Defines the ticks to be drawn on the tick bar. + /// + public AvaloniaList Ticks + { + get => GetValue(TicksProperty); + set => SetValue(TicksProperty, value); + } + /// /// Gets or sets the orientation of a . /// @@ -240,19 +257,50 @@ namespace Avalonia.Controls /// Value that want to snap to closest Tick. private double SnapToTick(double value) { - var previous = Minimum; - var next = Maximum; - - if (TickFrequency > 0.0) + if (IsSnapToTickEnabled) { - previous = Minimum + (Math.Round((value - Minimum) / TickFrequency) * TickFrequency); - next = Math.Min(Maximum, previous + TickFrequency); + double previous = Minimum; + double next = Maximum; + + // This property is rarely set so let's try to avoid the GetValue + var ticks = Ticks; + + // If ticks collection is available, use it. + // Note that ticks may be unsorted. + if ((ticks != null) && (ticks.Count > 0)) + { + for (int i = 0; i < ticks.Count; i++) + { + double tick = ticks[i]; + if (MathUtilities.AreClose(tick, value)) + { + return value; + } + + if (MathUtilities.LessThan(tick, value) && MathUtilities.GreaterThan(tick, previous)) + { + previous = tick; + } + else if (MathUtilities.GreaterThan(tick, value) && MathUtilities.LessThan(tick, next)) + { + next = tick; + } + } + } + else if (MathUtilities.GreaterThan(TickFrequency, 0.0)) + { + previous = Minimum + (Math.Round(((value - Minimum) / TickFrequency)) * TickFrequency); + next = Math.Min(Maximum, previous + TickFrequency); + } + + // Choose the closest value between previous and next. If tie, snap to 'next'. + value = MathUtilities.GreaterThanOrClose(value, (previous + next) * 0.5) ? next : previous; } - // Choose the closest value between previous and next. If tie, snap to 'next'. - return MathUtilities.GreaterThanOrClose(value, (previous + next) * 0.5) ? next : previous; + return value; } + private void UpdatePseudoClasses(Orientation o) { PseudoClasses.Set(":vertical", o == Orientation.Vertical); diff --git a/src/Avalonia.Controls/TickBar.cs b/src/Avalonia.Controls/TickBar.cs index 16e063beb3..22145d8742 100644 --- a/src/Avalonia.Controls/TickBar.cs +++ b/src/Avalonia.Controls/TickBar.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using Avalonia.Controls.Primitives; -using Avalonia.Data; -using Avalonia.Data.Converters; +using Avalonia.Collections; using Avalonia.Layout; using Avalonia.Media; using Avalonia.Utilities; @@ -135,15 +131,15 @@ namespace Avalonia.Controls /// /// Defines the property. /// - public static readonly StyledProperty> TicksProperty = - AvaloniaProperty.Register>(nameof(Ticks)); + public static readonly StyledProperty> TicksProperty = + AvaloniaProperty.Register>(nameof(Ticks)); /// /// The Ticks property contains collection of value of type Double which /// are the logical positions use to draw the ticks. /// The property value is a . /// - public List Ticks + public AvaloniaList Ticks { get { return GetValue(TicksProperty); } set { SetValue(TicksProperty, value); } diff --git a/src/Avalonia.Themes.Default/Slider.xaml b/src/Avalonia.Themes.Default/Slider.xaml index 1d48a946fc..ba4b1ee998 100644 --- a/src/Avalonia.Themes.Default/Slider.xaml +++ b/src/Avalonia.Themes.Default/Slider.xaml @@ -87,7 +87,10 @@ - + + diff --git a/src/Avalonia.Themes.Fluent/Slider.xaml b/src/Avalonia.Themes.Fluent/Slider.xaml index 539c448e0f..099c2000b8 100644 --- a/src/Avalonia.Themes.Fluent/Slider.xaml +++ b/src/Avalonia.Themes.Fluent/Slider.xaml @@ -182,6 +182,7 @@