|
@@ -1,430 +0,0 @@
|
|
|
-using System;
|
|
|
-using System.Collections.Generic;
|
|
|
-using Avalonia.Controls.Primitives;
|
|
|
-using Avalonia.Data;
|
|
|
-using Avalonia.Data.Converters;
|
|
|
-using Avalonia.Layout;
|
|
|
-using Avalonia.Media;
|
|
|
-using Avalonia.Utilities;
|
|
|
-
|
|
|
-namespace Avalonia.Controls
|
|
|
-{
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Enum which describes how to position the TickBar.
|
|
|
- /// </summary>
|
|
|
- public enum TickBarPlacement
|
|
|
- {
|
|
|
- /// <summary>
|
|
|
- /// Position this tick at the left of target element.
|
|
|
- /// </summary>
|
|
|
- Left,
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Position this tick at the top of target element.
|
|
|
- /// </summary>
|
|
|
- Top,
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Position this tick at the right of target element.
|
|
|
- /// </summary>
|
|
|
- Right,
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Position this tick at the bottom of target element.
|
|
|
- /// </summary>
|
|
|
- Bottom,
|
|
|
-
|
|
|
- // NOTE: if you add or remove any values in this enum, be sure to update TickBar.IsValidTickBarPlacement()
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// TickBar is an element that use for drawing Slider's Ticks.
|
|
|
- /// </summary>
|
|
|
- public class TickBar : Control
|
|
|
- {
|
|
|
- static TickBar()
|
|
|
- {
|
|
|
- AffectsRender<TickBar>(ReservedSpaceProperty,
|
|
|
- MaximumProperty,
|
|
|
- MinimumProperty,
|
|
|
- OrientationProperty,
|
|
|
- TickFrequencyProperty);
|
|
|
- }
|
|
|
-
|
|
|
- public TickBar() : base()
|
|
|
- {
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="Fill"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<IBrush> FillProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, IBrush>(nameof(Fill));
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Brush used to fill the TickBar's Ticks.
|
|
|
- /// </summary>
|
|
|
- public IBrush Fill
|
|
|
- {
|
|
|
- get { return GetValue(FillProperty); }
|
|
|
- set { SetValue(FillProperty, value); }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="Minimum"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<double> MinimumProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, double>(nameof(Minimum), 0d);
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Logical position where the Minimum Tick will be drawn
|
|
|
- /// </summary>
|
|
|
- public double Minimum
|
|
|
- {
|
|
|
- get { return GetValue(MinimumProperty); }
|
|
|
- set
|
|
|
- {
|
|
|
- SetValue(MinimumProperty, value);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="Maximum"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<double> MaximumProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, double>(nameof(Maximum), 0d);
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Logical position where the Maximum Tick will be drawn
|
|
|
- /// </summary>
|
|
|
- public double Maximum
|
|
|
- {
|
|
|
- get { return GetValue(MaximumProperty); }
|
|
|
- set { SetValue(MaximumProperty, value); }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="TickFrequency"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<double> TickFrequencyProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, double>(nameof(TickFrequency), 0d);
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// TickFrequency property defines how the tick will be drawn.
|
|
|
- /// </summary>
|
|
|
- public double TickFrequency
|
|
|
- {
|
|
|
- get { return GetValue(TickFrequencyProperty); }
|
|
|
- set { SetValue(TickFrequencyProperty, value); }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="Orientation"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<Orientation> OrientationProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, Orientation>(nameof(Orientation));
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// TickBar parent's orientation.
|
|
|
- /// </summary>
|
|
|
- public Orientation Orientation
|
|
|
- {
|
|
|
- get { return GetValue(OrientationProperty); }
|
|
|
- set { SetValue(OrientationProperty, value); }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="Ticks"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<List<double>> TicksProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, List<double>>(nameof(Ticks));
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// 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 <see cref="DoubleCollection" />.
|
|
|
- /// </summary>
|
|
|
- public List<double> Ticks
|
|
|
- {
|
|
|
- get { return GetValue(TicksProperty); }
|
|
|
- set { SetValue(TicksProperty, value); }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="IsDirectionReversed"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<bool> IsDirectionReversedProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, bool>(nameof(IsDirectionReversed), false);
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// The IsDirectionReversed property defines the direction of value incrementation.
|
|
|
- /// By default, if Tick's orientation is Horizontal, ticks will be drawn from left to right.
|
|
|
- /// (And, bottom to top for Vertical orientation).
|
|
|
- /// If IsDirectionReversed is 'true' the direction of the drawing will be in opposite direction.
|
|
|
- /// </summary>
|
|
|
- public bool IsDirectionReversed
|
|
|
- {
|
|
|
- get { return GetValue(IsDirectionReversedProperty); }
|
|
|
- set { SetValue(IsDirectionReversedProperty, value); }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="Placement"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<TickBarPlacement> PlacementProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, TickBarPlacement>(nameof(Placement), 0d);
|
|
|
-
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Placement property specified how the Tick will be placed.
|
|
|
- /// This property affects the way ticks are drawn.
|
|
|
- /// This property has type of <see cref="TickBarPlacement" />.
|
|
|
- /// </summary>
|
|
|
- public TickBarPlacement Placement
|
|
|
- {
|
|
|
- get { return GetValue(PlacementProperty); }
|
|
|
- set { SetValue(PlacementProperty, value); }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Defines the <see cref="ReservedSpace"/> property.
|
|
|
- /// </summary>
|
|
|
- public static readonly StyledProperty<Rect> ReservedSpaceProperty =
|
|
|
- AvaloniaProperty.Register<TickBar, Rect>(nameof(ReservedSpace));
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// TickBar will use ReservedSpaceProperty for left and right spacing (for horizontal orientation) or
|
|
|
- /// tob and bottom spacing (for vertical orienation).
|
|
|
- /// The space on both sides of TickBar is half of specified ReservedSpace.
|
|
|
- /// This property has type of <see cref="Rect" />.
|
|
|
- /// </summary>
|
|
|
- public Rect ReservedSpace
|
|
|
- {
|
|
|
- get { return GetValue(ReservedSpaceProperty); }
|
|
|
- set { SetValue(ReservedSpaceProperty, value); }
|
|
|
- }
|
|
|
-
|
|
|
- protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
|
|
|
- {
|
|
|
- base.OnPropertyChanged(change);
|
|
|
-
|
|
|
- if (change.Property == ReservedSpaceProperty)
|
|
|
- {
|
|
|
- // UpdatePseudoClasses(change.NewValue.GetValueOrDefault<Location>());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Draw ticks.
|
|
|
- /// Ticks can be draw in 8 diffrent ways depends on Placment property and IsDirectionReversed property.
|
|
|
- ///
|
|
|
- /// This function also draw selection-tick(s) if IsSelectionRangeEnabled is 'true' and
|
|
|
- /// SelectionStart and SelectionEnd are valid.
|
|
|
- ///
|
|
|
- /// The primary ticks (for Mininum and Maximum value) height will be 100% of TickBar's render size (use Width or Height
|
|
|
- /// depends on Placement property).
|
|
|
- ///
|
|
|
- /// The secondary ticks (all other ticks, including selection-tics) height will be 75% of TickBar's render size.
|
|
|
- ///
|
|
|
- /// Brush that use to fill ticks is specified by Shape.Fill property.
|
|
|
- ///
|
|
|
- /// Pen that use to draw ticks is specified by Shape.Pen property.
|
|
|
- /// </summary>
|
|
|
- public override void Render(DrawingContext dc)
|
|
|
- {
|
|
|
- var size = new Size(Bounds.Width, Bounds.Height);
|
|
|
- var range = Maximum - Minimum;
|
|
|
- var tickLen = 0.0d; // Height for Primary Tick (for Mininum and Maximum value)
|
|
|
- var tickLen2 = 0.0d; // Height for Secondary Tick
|
|
|
- var logicalToPhysical = 1.0;
|
|
|
- var progression = 1.0d;
|
|
|
- var startPoint = new Point();
|
|
|
- var endPoint = new Point();
|
|
|
- var rSpace = Orientation == Orientation.Horizontal ? ReservedSpace.Width : ReservedSpace.Height;
|
|
|
-
|
|
|
- // Take Thumb size in to account
|
|
|
- double halfReservedSpace = rSpace * 0.5;
|
|
|
-
|
|
|
- switch (Placement)
|
|
|
- {
|
|
|
- case TickBarPlacement.Top:
|
|
|
- if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- size = new Size(size.Width - rSpace, size.Height);
|
|
|
- tickLen = -size.Height;
|
|
|
- startPoint = new Point(halfReservedSpace, size.Height);
|
|
|
- endPoint = new Point(halfReservedSpace + size.Width, size.Height);
|
|
|
- logicalToPhysical = size.Width / range;
|
|
|
- progression = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case TickBarPlacement.Bottom:
|
|
|
- if (MathUtilities.GreaterThanOrClose(rSpace, size.Width))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- size = new Size(size.Width - rSpace, size.Height);
|
|
|
- tickLen = size.Height;
|
|
|
- startPoint = new Point(halfReservedSpace, 0d);
|
|
|
- endPoint = new Point(halfReservedSpace + size.Width, 0d);
|
|
|
- logicalToPhysical = size.Width / range;
|
|
|
- progression = 1;
|
|
|
- break;
|
|
|
-
|
|
|
- case TickBarPlacement.Left:
|
|
|
- if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- size = new Size(size.Width, size.Height - rSpace);
|
|
|
-
|
|
|
- tickLen = -size.Width;
|
|
|
- startPoint = new Point(size.Width, size.Height + halfReservedSpace);
|
|
|
- endPoint = new Point(size.Width, halfReservedSpace);
|
|
|
- logicalToPhysical = size.Height / range * -1;
|
|
|
- progression = -1;
|
|
|
- break;
|
|
|
-
|
|
|
- case TickBarPlacement.Right:
|
|
|
- if (MathUtilities.GreaterThanOrClose(rSpace, size.Height))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- size = new Size(size.Width, size.Height - rSpace);
|
|
|
-
|
|
|
- tickLen = size.Width;
|
|
|
- startPoint = new Point(0d, size.Height + halfReservedSpace);
|
|
|
- endPoint = new Point(0d, halfReservedSpace);
|
|
|
- logicalToPhysical = size.Height / range * -1;
|
|
|
- progression = -1;
|
|
|
- break;
|
|
|
- };
|
|
|
-
|
|
|
- tickLen2 = tickLen * 0.75;
|
|
|
-
|
|
|
- // Invert direciton of the ticks
|
|
|
- if (IsDirectionReversed)
|
|
|
- {
|
|
|
- progression *= -progression;
|
|
|
- logicalToPhysical *= -1;
|
|
|
-
|
|
|
- // swap startPoint & endPoint
|
|
|
- var pt = startPoint;
|
|
|
- startPoint = endPoint;
|
|
|
- endPoint = pt;
|
|
|
- }
|
|
|
-
|
|
|
- var pen = new Pen(Fill, 1.0d);
|
|
|
-
|
|
|
- // Is it Vertical?
|
|
|
- if ((Placement == TickBarPlacement.Left) || (Placement == TickBarPlacement.Right))
|
|
|
- {
|
|
|
- // Reduce tick interval if it is more than would be visible on the screen
|
|
|
- double interval = TickFrequency;
|
|
|
- if (interval > 0.0)
|
|
|
- {
|
|
|
- double minInterval = (Maximum - Minimum) / size.Height;
|
|
|
- if (interval < minInterval)
|
|
|
- {
|
|
|
- interval = minInterval;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Draw Min & Max tick
|
|
|
- dc.DrawLine(pen, startPoint, new Point(startPoint.X + tickLen, startPoint.Y));
|
|
|
- dc.DrawLine(pen, new Point(startPoint.X, endPoint.Y),
|
|
|
- new Point(startPoint.X + tickLen, endPoint.Y));
|
|
|
-
|
|
|
- // This property is rarely set so let's try to avoid the GetValue
|
|
|
- // caching of the mutable default value
|
|
|
- var ticks = Ticks ?? null;
|
|
|
-
|
|
|
- // Draw ticks using specified Ticks collection
|
|
|
- if (ticks?.Count > 0)
|
|
|
- {
|
|
|
- for (int i = 0; i < ticks.Count; i++)
|
|
|
- {
|
|
|
- if (MathUtilities.LessThanOrClose(ticks[i], Minimum) || MathUtilities.GreaterThanOrClose(ticks[i], Maximum))
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- double adjustedTick = ticks[i] - Minimum;
|
|
|
-
|
|
|
- double y = adjustedTick * logicalToPhysical + startPoint.Y;
|
|
|
- dc.DrawLine(pen,
|
|
|
- new Point(startPoint.X, y),
|
|
|
- new Point(startPoint.X + tickLen2, y));
|
|
|
- }
|
|
|
- }
|
|
|
- // Draw ticks using specified TickFrequency
|
|
|
- else if (interval > 0.0)
|
|
|
- {
|
|
|
- for (double i = interval; i < range; i += interval)
|
|
|
- {
|
|
|
- double y = i * logicalToPhysical + startPoint.Y;
|
|
|
-
|
|
|
- dc.DrawLine(pen,
|
|
|
- new Point(startPoint.X, y),
|
|
|
- new Point(startPoint.X + tickLen2, y));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else // Placement == Top || Placement == Bottom
|
|
|
- {
|
|
|
- // Reduce tick interval if it is more than would be visible on the screen
|
|
|
- double interval = TickFrequency;
|
|
|
- if (interval > 0.0)
|
|
|
- {
|
|
|
- double minInterval = (Maximum - Minimum) / size.Width;
|
|
|
- if (interval < minInterval)
|
|
|
- {
|
|
|
- interval = minInterval;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Draw Min & Max tick
|
|
|
- dc.DrawLine(pen, startPoint, new Point(startPoint.X, startPoint.Y + tickLen));
|
|
|
- dc.DrawLine(pen, new Point(endPoint.X, startPoint.Y),
|
|
|
- new Point(endPoint.X, startPoint.Y + tickLen));
|
|
|
-
|
|
|
- // This property is rarely set so let's try to avoid the GetValue
|
|
|
- // caching of the mutable default value
|
|
|
- var ticks = Ticks ?? null;
|
|
|
-
|
|
|
- // Draw ticks using specified Ticks collection
|
|
|
- if (ticks?.Count > 0)
|
|
|
- {
|
|
|
- for (int i = 0; i < ticks.Count; i++)
|
|
|
- {
|
|
|
- if (MathUtilities.LessThanOrClose(ticks[i], Minimum) || MathUtilities.GreaterThanOrClose(ticks[i], Maximum))
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- double adjustedTick = ticks[i] - Minimum;
|
|
|
-
|
|
|
- double x = adjustedTick * logicalToPhysical + startPoint.X;
|
|
|
- dc.DrawLine(pen,
|
|
|
- new Point(x, startPoint.Y),
|
|
|
- new Point(x, startPoint.Y + tickLen2));
|
|
|
- }
|
|
|
- }
|
|
|
- // Draw ticks using specified TickFrequency
|
|
|
- else if (interval > 0.0)
|
|
|
- {
|
|
|
- for (double i = interval; i < range; i += interval)
|
|
|
- {
|
|
|
- double x = i * logicalToPhysical + startPoint.X;
|
|
|
- dc.DrawLine(pen,
|
|
|
- new Point(x, startPoint.Y),
|
|
|
- new Point(x, startPoint.Y + tickLen2));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|