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;
///
/// A control used to indicate the progress of an operation.
///
[PseudoClasses(":preserveaspect", ":indeterminate")]
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public class ProgressRing : RangeBase
{
private Arc? fillArc;
public static readonly StyledProperty IsIndeterminateProperty = ProgressBar
.IsIndeterminateProperty
.AddOwner();
public bool IsIndeterminate
{
get => GetValue(IsIndeterminateProperty);
set => SetValue(IsIndeterminateProperty, value);
}
public static readonly StyledProperty PreserveAspectProperty = AvaloniaProperty.Register(
nameof(PreserveAspect),
true
);
public bool PreserveAspect
{
get => GetValue(PreserveAspectProperty);
set => SetValue(PreserveAspectProperty, value);
}
public static readonly StyledProperty StrokeThicknessProperty = Shape
.StrokeThicknessProperty
.AddOwner();
public double StrokeThickness
{
get => GetValue(StrokeThicknessProperty);
set => SetValue(StrokeThicknessProperty, value);
}
public static readonly StyledProperty StartAngleProperty = AvaloniaProperty.Register(
nameof(StartAngle)
);
public double StartAngle
{
get => GetValue(StartAngleProperty);
set => SetValue(StartAngleProperty, value);
}
public static readonly StyledProperty SweepAngleProperty = AvaloniaProperty.Register(
nameof(SweepAngle)
);
public double SweepAngle
{
get => GetValue(SweepAngleProperty);
set => SetValue(SweepAngleProperty, value);
}
public static readonly StyledProperty EndAngleProperty = AvaloniaProperty.Register(
nameof(EndAngle),
360
);
public double EndAngle
{
get => GetValue(EndAngleProperty);
set => SetValue(EndAngleProperty, value);
}
static ProgressRing()
{
AffectsRender(SweepAngleProperty, StartAngleProperty, EndAngleProperty);
ValueProperty.Changed.AddClassHandler(OnValuePropertyChanged);
SweepAngleProperty.Changed.AddClassHandler(OnSweepAnglePropertyChanged);
}
public ProgressRing()
{
UpdatePseudoClasses(IsIndeterminate, PreserveAspect);
}
///
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
fillArc = e.NameScope.Find("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;
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());
}
}
}