|
|
|
@ -1,8 +1,10 @@
|
|
|
|
|
using System.Diagnostics.CodeAnalysis; |
|
|
|
|
using System; |
|
|
|
|
using System.Diagnostics.CodeAnalysis; |
|
|
|
|
using Avalonia; |
|
|
|
|
using Avalonia.Controls; |
|
|
|
|
using Avalonia.Controls.Metadata; |
|
|
|
|
using Avalonia.Controls.Primitives; |
|
|
|
|
using Avalonia.Controls.Shapes; |
|
|
|
|
|
|
|
|
|
namespace StabilityMatrix.Avalonia.Controls; |
|
|
|
|
|
|
|
|
@ -13,70 +15,102 @@ namespace StabilityMatrix.Avalonia.Controls;
|
|
|
|
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] |
|
|
|
|
public class ProgressRing : RangeBase |
|
|
|
|
{ |
|
|
|
|
private Arc? fillArc; |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<bool> IsIndeterminateProperty = |
|
|
|
|
ProgressBar.IsIndeterminateProperty.AddOwner<ProgressRing>(); |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<bool> PreserveAspectProperty = |
|
|
|
|
AvaloniaProperty.Register<ProgressRing, bool>(nameof(PreserveAspect), true); |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<double> ValueAngleProperty = |
|
|
|
|
AvaloniaProperty.Register<ProgressRing, double>(nameof(ValueAngle)); |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<double> StartAngleProperty = |
|
|
|
|
AvaloniaProperty.Register<ProgressRing, double>(nameof(StartAngle)); |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<double> EndAngleProperty = |
|
|
|
|
AvaloniaProperty.Register<ProgressRing, double>(nameof(EndAngle), 360); |
|
|
|
|
|
|
|
|
|
static ProgressRing() |
|
|
|
|
{ |
|
|
|
|
MinimumProperty.Changed.AddClassHandler<ProgressRing>(OnMinimumPropertyChanged); |
|
|
|
|
MaximumProperty.Changed.AddClassHandler<ProgressRing>(OnMaximumPropertyChanged); |
|
|
|
|
ValueProperty.Changed.AddClassHandler<ProgressRing>(OnValuePropertyChanged); |
|
|
|
|
MaximumProperty.Changed.AddClassHandler<ProgressRing>(OnStartAnglePropertyChanged); |
|
|
|
|
MaximumProperty.Changed.AddClassHandler<ProgressRing>(OnEndAnglePropertyChanged); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public ProgressRing() |
|
|
|
|
{ |
|
|
|
|
UpdatePseudoClasses(IsIndeterminate, PreserveAspect); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public bool IsIndeterminate |
|
|
|
|
{ |
|
|
|
|
get => GetValue(IsIndeterminateProperty); |
|
|
|
|
set => SetValue(IsIndeterminateProperty, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<bool> PreserveAspectProperty = AvaloniaProperty.Register< |
|
|
|
|
ProgressRing, |
|
|
|
|
bool |
|
|
|
|
>(nameof(PreserveAspect), true); |
|
|
|
|
|
|
|
|
|
public bool PreserveAspect |
|
|
|
|
{ |
|
|
|
|
get => GetValue(PreserveAspectProperty); |
|
|
|
|
set => SetValue(PreserveAspectProperty, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public double ValueAngle |
|
|
|
|
public static readonly StyledProperty<double> StrokeThicknessProperty = |
|
|
|
|
Shape.StrokeThicknessProperty.AddOwner<ProgressRing>(); |
|
|
|
|
|
|
|
|
|
public double StrokeThickness |
|
|
|
|
{ |
|
|
|
|
get => GetValue(ValueAngleProperty); |
|
|
|
|
private set => SetValue(ValueAngleProperty, value); |
|
|
|
|
get => GetValue(StrokeThicknessProperty); |
|
|
|
|
set => SetValue(StrokeThicknessProperty, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<double> StartAngleProperty = AvaloniaProperty.Register< |
|
|
|
|
ProgressRing, |
|
|
|
|
double |
|
|
|
|
>(nameof(StartAngle)); |
|
|
|
|
|
|
|
|
|
public double StartAngle |
|
|
|
|
{ |
|
|
|
|
get => GetValue(StartAngleProperty); |
|
|
|
|
set => SetValue(StartAngleProperty, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<double> SweepAngleProperty = AvaloniaProperty.Register< |
|
|
|
|
ProgressRing, |
|
|
|
|
double |
|
|
|
|
>(nameof(SweepAngle)); |
|
|
|
|
|
|
|
|
|
public double SweepAngle |
|
|
|
|
{ |
|
|
|
|
get => GetValue(SweepAngleProperty); |
|
|
|
|
set => SetValue(SweepAngleProperty, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static readonly StyledProperty<double> EndAngleProperty = AvaloniaProperty.Register< |
|
|
|
|
ProgressRing, |
|
|
|
|
double |
|
|
|
|
>(nameof(EndAngle), 360); |
|
|
|
|
|
|
|
|
|
public double EndAngle |
|
|
|
|
{ |
|
|
|
|
get => GetValue(EndAngleProperty); |
|
|
|
|
set => SetValue(EndAngleProperty, value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static ProgressRing() |
|
|
|
|
{ |
|
|
|
|
AffectsRender<ProgressRing>(SweepAngleProperty, StartAngleProperty, EndAngleProperty); |
|
|
|
|
|
|
|
|
|
ValueProperty.Changed.AddClassHandler<ProgressRing>(OnValuePropertyChanged); |
|
|
|
|
SweepAngleProperty.Changed.AddClassHandler<ProgressRing>(OnSweepAnglePropertyChanged); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public ProgressRing() |
|
|
|
|
{ |
|
|
|
|
UpdatePseudoClasses(IsIndeterminate, PreserveAspect); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <inheritdoc /> |
|
|
|
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) |
|
|
|
|
{ |
|
|
|
|
base.OnApplyTemplate(e); |
|
|
|
|
|
|
|
|
|
fillArc = e.NameScope.Find<Arc>("PART_Fill"); |
|
|
|
|
if (fillArc is not null) |
|
|
|
|
{ |
|
|
|
|
fillArc.StartAngle = StartAngle; |
|
|
|
|
fillArc.SweepAngle = SweepAngle; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) |
|
|
|
|
{ |
|
|
|
|
base.OnPropertyChanged(change); |
|
|
|
|
var e = change as AvaloniaPropertyChangedEventArgs<bool>; |
|
|
|
|
if (e is null) return; |
|
|
|
|
if (e is null) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
if (e.Property == IsIndeterminateProperty) |
|
|
|
|
{ |
|
|
|
@ -88,9 +122,7 @@ public class ProgressRing : RangeBase
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void UpdatePseudoClasses( |
|
|
|
|
bool? isIndeterminate, |
|
|
|
|
bool? preserveAspect) |
|
|
|
|
private void UpdatePseudoClasses(bool? isIndeterminate, bool? preserveAspect) |
|
|
|
|
{ |
|
|
|
|
if (isIndeterminate.HasValue) |
|
|
|
|
{ |
|
|
|
@ -103,28 +135,25 @@ public class ProgressRing : RangeBase
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void OnMinimumPropertyChanged(ProgressRing sender, AvaloniaPropertyChangedEventArgs e) |
|
|
|
|
{ |
|
|
|
|
sender.Minimum = (double) e.NewValue!; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void OnMaximumPropertyChanged(ProgressRing sender, AvaloniaPropertyChangedEventArgs e) |
|
|
|
|
{ |
|
|
|
|
sender.Maximum = (double) e.NewValue!; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void OnValuePropertyChanged(ProgressRing sender, AvaloniaPropertyChangedEventArgs e) |
|
|
|
|
{ |
|
|
|
|
sender.ValueAngle = ((double) e.NewValue! - sender.Minimum) * (sender.EndAngle - sender.StartAngle) / (sender.Maximum - sender.Minimum); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void OnStartAnglePropertyChanged(ProgressRing sender, AvaloniaPropertyChangedEventArgs e) |
|
|
|
|
private static void OnValuePropertyChanged( |
|
|
|
|
ProgressRing sender, |
|
|
|
|
AvaloniaPropertyChangedEventArgs e |
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
sender.StartAngle = (double) e.NewValue!; |
|
|
|
|
sender.SweepAngle = |
|
|
|
|
((double)e.NewValue! - sender.Minimum) |
|
|
|
|
* (sender.EndAngle - sender.StartAngle) |
|
|
|
|
/ (sender.Maximum - sender.Minimum); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static void OnEndAnglePropertyChanged(ProgressRing sender, AvaloniaPropertyChangedEventArgs e) |
|
|
|
|
private static void OnSweepAnglePropertyChanged( |
|
|
|
|
ProgressRing sender, |
|
|
|
|
AvaloniaPropertyChangedEventArgs e |
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
sender.EndAngle = (double) e.NewValue!; |
|
|
|
|
if (sender.fillArc is { } arc) |
|
|
|
|
{ |
|
|
|
|
arc.SweepAngle = Math.Round(e.GetNewValue<double>()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|