using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Animation;
using Avalonia.Collections;
using Avalonia.Media.Immutable;
using Avalonia.Reactive;
#nullable enable
namespace Avalonia.Media
{
///
/// Represents the sequence of dashes and gaps that will be applied by a .
///
public class DashStyle : Animatable, IDashStyle, IAffectsRender
{
///
/// Defines the property.
///
public static readonly StyledProperty?> DashesProperty =
AvaloniaProperty.Register?>(nameof(Dashes));
///
/// Defines the property.
///
public static readonly StyledProperty OffsetProperty =
AvaloniaProperty.Register(nameof(Offset));
private static ImmutableDashStyle? s_dash;
private static ImmutableDashStyle? s_dot;
private static ImmutableDashStyle? s_dashDot;
private static ImmutableDashStyle? s_dashDotDot;
///
/// Initializes a new instance of the class.
///
public DashStyle()
{
}
///
/// Initializes a new instance of the class.
///
/// The dashes collection.
/// The dash sequence offset.
public DashStyle(IEnumerable? dashes, double offset)
{
Dashes = (dashes as AvaloniaList) ?? new AvaloniaList(dashes ?? Array.Empty());
Offset = offset;
}
static DashStyle()
{
var invalidateObserver = new AnonymousObserver(
static e => ((DashStyle)e.Sender).Invalidated?.Invoke(e.Sender, EventArgs.Empty));
DashesProperty.Changed.Subscribe(invalidateObserver);
OffsetProperty.Changed.Subscribe(invalidateObserver);
}
///
/// Represents a dashed .
///
public static IDashStyle Dash => s_dash ??= new ImmutableDashStyle(new double[] { 2, 2 }, 1);
///
/// Represents a dotted .
///
public static IDashStyle Dot => s_dot ??= new ImmutableDashStyle(new double[] { 0, 2 }, 0);
///
/// Represents a dashed dotted .
///
public static IDashStyle DashDot => s_dashDot ??= new ImmutableDashStyle(new double[] { 2, 2, 0, 2 }, 1);
///
/// Represents a dashed double dotted .
///
public static IDashStyle DashDotDot => s_dashDotDot ??= new ImmutableDashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1);
///
/// Gets or sets the length of alternating dashes and gaps.
///
public AvaloniaList? Dashes
{
get => GetValue(DashesProperty);
set => SetValue(DashesProperty, value);
}
///
/// Gets or sets how far in the dash sequence the stroke will start.
///
public double Offset
{
get => GetValue(OffsetProperty);
set => SetValue(OffsetProperty, value);
}
IReadOnlyList? IDashStyle.Dashes => Dashes;
///
/// Raised when the dash style changes.
///
public event EventHandler? Invalidated;
///
/// Returns an immutable clone of the .
///
///
public ImmutableDashStyle ToImmutable() => new ImmutableDashStyle(Dashes, Offset);
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == DashesProperty)
{
var (oldValue, newValue) = change.GetOldAndNewValue>();
if (oldValue is object)
{
oldValue.CollectionChanged -= DashesChanged;
}
if (newValue is object)
{
newValue.CollectionChanged += DashesChanged;
}
}
}
private void DashesChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
Invalidated?.Invoke(this, e);
}
}
}