|
|
@ -1,3 +1,7 @@ |
|
|
|
|
|
#nullable enable |
|
|
|
|
|
using System; |
|
|
|
|
|
using System.Linq; |
|
|
|
|
|
using Avalonia.Collections; |
|
|
using Avalonia.Metadata; |
|
|
using Avalonia.Metadata; |
|
|
|
|
|
|
|
|
namespace Avalonia.Media |
|
|
namespace Avalonia.Media |
|
|
@ -8,22 +12,36 @@ namespace Avalonia.Media |
|
|
/// Defines the <see cref="IsClosed"/> property.
|
|
|
/// Defines the <see cref="IsClosed"/> property.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public static readonly StyledProperty<bool> IsClosedProperty |
|
|
public static readonly StyledProperty<bool> IsClosedProperty |
|
|
= AvaloniaProperty.Register<PathFigure, bool>(nameof(IsClosed), true); |
|
|
= AvaloniaProperty.Register<PathFigure, bool>(nameof(IsClosed), true); |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Defines the <see cref="IsFilled"/> property.
|
|
|
/// Defines the <see cref="IsFilled"/> property.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public static readonly StyledProperty<bool> IsFilledProperty |
|
|
public static readonly StyledProperty<bool> IsFilledProperty |
|
|
= AvaloniaProperty.Register<PathFigure, bool>(nameof(IsFilled), true); |
|
|
= AvaloniaProperty.Register<PathFigure, bool>(nameof(IsFilled), true); |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Defines the <see cref="Segments"/> property.
|
|
|
/// Defines the <see cref="Segments"/> property.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public static readonly DirectProperty<PathFigure, PathSegments> SegmentsProperty |
|
|
public static readonly DirectProperty<PathFigure, PathSegments?> SegmentsProperty |
|
|
= AvaloniaProperty.RegisterDirect<PathFigure, PathSegments>(nameof(Segments), f => f.Segments, (f, s) => f.Segments = s); |
|
|
= AvaloniaProperty.RegisterDirect<PathFigure, PathSegments?>( |
|
|
|
|
|
nameof(Segments), |
|
|
|
|
|
f => f.Segments, |
|
|
|
|
|
(f, s) => f.Segments = s); |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Defines the <see cref="StartPoint"/> property.
|
|
|
/// Defines the <see cref="StartPoint"/> property.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public static readonly StyledProperty<Point> StartPointProperty |
|
|
public static readonly StyledProperty<Point> StartPointProperty |
|
|
= AvaloniaProperty.Register<PathFigure, Point>(nameof(StartPoint)); |
|
|
= AvaloniaProperty.Register<PathFigure, Point>(nameof(StartPoint)); |
|
|
|
|
|
|
|
|
|
|
|
internal event EventHandler? SegmentsInvalidated; |
|
|
|
|
|
|
|
|
|
|
|
private PathSegments? _segments; |
|
|
|
|
|
|
|
|
|
|
|
private IDisposable? _segmentsDisposable; |
|
|
|
|
|
|
|
|
|
|
|
private IDisposable? _segmentsPropertiesDisposable; |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Initializes a new instance of the <see cref="PathFigure"/> class.
|
|
|
/// Initializes a new instance of the <see cref="PathFigure"/> class.
|
|
|
@ -33,6 +51,31 @@ namespace Avalonia.Media |
|
|
Segments = new PathSegments(); |
|
|
Segments = new PathSegments(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static PathFigure() |
|
|
|
|
|
{ |
|
|
|
|
|
SegmentsProperty.Changed.AddClassHandler<PathFigure>( |
|
|
|
|
|
(s, e) => |
|
|
|
|
|
s.OnSegmentsChanged()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void OnSegmentsChanged() |
|
|
|
|
|
{ |
|
|
|
|
|
_segmentsDisposable?.Dispose(); |
|
|
|
|
|
_segmentsPropertiesDisposable?.Dispose(); |
|
|
|
|
|
|
|
|
|
|
|
_segmentsDisposable = _segments?.ForEachItem( |
|
|
|
|
|
_ => InvalidateSegments(), |
|
|
|
|
|
_ => InvalidateSegments(), |
|
|
|
|
|
InvalidateSegments); |
|
|
|
|
|
|
|
|
|
|
|
_segmentsPropertiesDisposable = _segments?.TrackItemPropertyChanged(_ => InvalidateSegments()); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void InvalidateSegments() |
|
|
|
|
|
{ |
|
|
|
|
|
SegmentsInvalidated?.Invoke(this, EventArgs.Empty); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Gets or sets a value indicating whether this instance is closed.
|
|
|
/// Gets or sets a value indicating whether this instance is closed.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
@ -64,7 +107,7 @@ namespace Avalonia.Media |
|
|
/// The segments.
|
|
|
/// The segments.
|
|
|
/// </value>
|
|
|
/// </value>
|
|
|
[Content] |
|
|
[Content] |
|
|
public PathSegments Segments |
|
|
public PathSegments? Segments |
|
|
{ |
|
|
{ |
|
|
get { return _segments; } |
|
|
get { return _segments; } |
|
|
set { SetAndRaise(SegmentsProperty, ref _segments, value); } |
|
|
set { SetAndRaise(SegmentsProperty, ref _segments, value); } |
|
|
@ -81,22 +124,23 @@ namespace Avalonia.Media |
|
|
get { return GetValue(StartPointProperty); } |
|
|
get { return GetValue(StartPointProperty); } |
|
|
set { SetValue(StartPointProperty, value); } |
|
|
set { SetValue(StartPointProperty, value); } |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public override string ToString() |
|
|
|
|
|
=> $"M {StartPoint} {string.Join(" ", _segments ?? Enumerable.Empty<PathSegment>())}{(IsClosed ? "Z" : "")}"; |
|
|
|
|
|
|
|
|
internal void ApplyTo(StreamGeometryContext ctx) |
|
|
internal void ApplyTo(StreamGeometryContext ctx) |
|
|
{ |
|
|
{ |
|
|
ctx.BeginFigure(StartPoint, IsFilled); |
|
|
ctx.BeginFigure(StartPoint, IsFilled); |
|
|
|
|
|
|
|
|
foreach (var segment in Segments) |
|
|
if (Segments != null) |
|
|
{ |
|
|
{ |
|
|
segment.ApplyTo(ctx); |
|
|
foreach (var segment in Segments) |
|
|
|
|
|
{ |
|
|
|
|
|
segment.ApplyTo(ctx); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ctx.EndFigure(IsClosed); |
|
|
ctx.EndFigure(IsClosed); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private PathSegments _segments; |
|
|
|
|
|
|
|
|
|
|
|
public override string ToString() |
|
|
|
|
|
=> $"M {StartPoint} {string.Join(" ", _segments)}{(IsClosed ? "Z" : "")}"; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|