You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
4.5 KiB
159 lines
4.5 KiB
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; |
|
|
|
/// <summary> |
|
/// A control used to indicate the progress of an operation. |
|
/// </summary> |
|
[PseudoClasses(":preserveaspect", ":indeterminate")] |
|
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] |
|
public class ProgressRing : RangeBase |
|
{ |
|
private Arc? fillArc; |
|
|
|
public static readonly StyledProperty<bool> IsIndeterminateProperty = |
|
ProgressBar.IsIndeterminateProperty.AddOwner<ProgressRing>(); |
|
|
|
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 static readonly StyledProperty<double> StrokeThicknessProperty = |
|
Shape.StrokeThicknessProperty.AddOwner<ProgressRing>(); |
|
|
|
public double StrokeThickness |
|
{ |
|
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.Property == IsIndeterminateProperty) |
|
{ |
|
UpdatePseudoClasses(e.NewValue.GetValueOrDefault(), null); |
|
} |
|
else if (e.Property == PreserveAspectProperty) |
|
{ |
|
UpdatePseudoClasses(null, e.NewValue.GetValueOrDefault()); |
|
} |
|
} |
|
|
|
private void UpdatePseudoClasses(bool? isIndeterminate, bool? preserveAspect) |
|
{ |
|
if (isIndeterminate.HasValue) |
|
{ |
|
PseudoClasses.Set(":indeterminate", isIndeterminate.Value); |
|
} |
|
|
|
if (preserveAspect.HasValue) |
|
{ |
|
PseudoClasses.Set(":preserveaspect", preserveAspect.Value); |
|
} |
|
} |
|
|
|
private static void OnValuePropertyChanged( |
|
ProgressRing sender, |
|
AvaloniaPropertyChangedEventArgs e |
|
) |
|
{ |
|
sender.SweepAngle = |
|
((double)e.NewValue! - sender.Minimum) |
|
* (sender.EndAngle - sender.StartAngle) |
|
/ (sender.Maximum - sender.Minimum); |
|
} |
|
|
|
private static void OnSweepAnglePropertyChanged( |
|
ProgressRing sender, |
|
AvaloniaPropertyChangedEventArgs e |
|
) |
|
{ |
|
if (sender.fillArc is { } arc) |
|
{ |
|
arc.SweepAngle = Math.Round(e.GetNewValue<double>()); |
|
} |
|
} |
|
}
|
|
|