|
@@ -1,13 +1,61 @@
|
|
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
|
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|
|
|
|
|
|
|
|
|
+using System;
|
|
|
|
|
+using System.Collections.Generic;
|
|
|
|
|
+using Avalonia.Media.Immutable;
|
|
|
|
|
+using Avalonia.Utilities;
|
|
|
|
|
+
|
|
|
namespace Avalonia.Media
|
|
namespace Avalonia.Media
|
|
|
{
|
|
{
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
/// Describes how a stroke is drawn.
|
|
/// Describes how a stroke is drawn.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
- public class Pen
|
|
|
|
|
|
|
+ public class Pen : AvaloniaObject, IPen
|
|
|
{
|
|
{
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Defines the <see cref="Brush"/> property.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public static readonly StyledProperty<IBrush> BrushProperty =
|
|
|
|
|
+ AvaloniaProperty.Register<Pen, IBrush>(nameof(Brush));
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Defines the <see cref="Thickness"/> property.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public static readonly StyledProperty<double> ThicknessProperty =
|
|
|
|
|
+ AvaloniaProperty.Register<Pen, double>(nameof(Thickness), 1.0);
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Defines the <see cref="DashStyle"/> property.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public static readonly StyledProperty<IDashStyle> DashStyleProperty =
|
|
|
|
|
+ AvaloniaProperty.Register<Pen, IDashStyle>(nameof(DashStyle));
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Defines the <see cref="LineCap"/> property.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public static readonly StyledProperty<PenLineCap> LineCapProperty =
|
|
|
|
|
+ AvaloniaProperty.Register<Pen, PenLineCap>(nameof(LineCap));
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Defines the <see cref="LineJoin"/> property.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public static readonly StyledProperty<PenLineJoin> LineJoinProperty =
|
|
|
|
|
+ AvaloniaProperty.Register<Pen, PenLineJoin>(nameof(LineJoin));
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Defines the <see cref="MiterLimit"/> property.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public static readonly StyledProperty<double> MiterLimitProperty =
|
|
|
|
|
+ AvaloniaProperty.Register<Pen, double>(nameof(MiterLimit), 10.0);
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Initializes a new instance of the <see cref="Pen"/> class.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public Pen()
|
|
|
|
|
+ {
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
/// Initializes a new instance of the <see cref="Pen"/> class.
|
|
/// Initializes a new instance of the <see cref="Pen"/> class.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
@@ -20,7 +68,7 @@ namespace Avalonia.Media
|
|
|
public Pen(
|
|
public Pen(
|
|
|
uint color,
|
|
uint color,
|
|
|
double thickness = 1.0,
|
|
double thickness = 1.0,
|
|
|
- DashStyle dashStyle = null,
|
|
|
|
|
|
|
+ IDashStyle dashStyle = null,
|
|
|
PenLineCap lineCap = PenLineCap.Flat,
|
|
PenLineCap lineCap = PenLineCap.Flat,
|
|
|
PenLineJoin lineJoin = PenLineJoin.Miter,
|
|
PenLineJoin lineJoin = PenLineJoin.Miter,
|
|
|
double miterLimit = 10.0) : this(new SolidColorBrush(color), thickness, dashStyle, lineCap, lineJoin, miterLimit)
|
|
double miterLimit = 10.0) : this(new SolidColorBrush(color), thickness, dashStyle, lineCap, lineJoin, miterLimit)
|
|
@@ -39,7 +87,7 @@ namespace Avalonia.Media
|
|
|
public Pen(
|
|
public Pen(
|
|
|
IBrush brush,
|
|
IBrush brush,
|
|
|
double thickness = 1.0,
|
|
double thickness = 1.0,
|
|
|
- DashStyle dashStyle = null,
|
|
|
|
|
|
|
+ IDashStyle dashStyle = null,
|
|
|
PenLineCap lineCap = PenLineCap.Flat,
|
|
PenLineCap lineCap = PenLineCap.Flat,
|
|
|
PenLineJoin lineJoin = PenLineJoin.Miter,
|
|
PenLineJoin lineJoin = PenLineJoin.Miter,
|
|
|
double miterLimit = 10.0)
|
|
double miterLimit = 10.0)
|
|
@@ -52,34 +100,139 @@ namespace Avalonia.Media
|
|
|
DashStyle = dashStyle;
|
|
DashStyle = dashStyle;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ static Pen()
|
|
|
|
|
+ {
|
|
|
|
|
+ AffectsRender<Pen>(
|
|
|
|
|
+ BrushProperty,
|
|
|
|
|
+ ThicknessProperty,
|
|
|
|
|
+ DashStyleProperty,
|
|
|
|
|
+ LineCapProperty,
|
|
|
|
|
+ LineJoinProperty,
|
|
|
|
|
+ MiterLimitProperty);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Gets or sets the brush used to draw the stroke.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public IBrush Brush
|
|
|
|
|
+ {
|
|
|
|
|
+ get => GetValue(BrushProperty);
|
|
|
|
|
+ set => SetValue(BrushProperty, value);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Gets or sets the stroke thickness.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public double Thickness
|
|
|
|
|
+ {
|
|
|
|
|
+ get => GetValue(ThicknessProperty);
|
|
|
|
|
+ set => SetValue(ThicknessProperty, value);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Gets or sets the style of dashed lines drawn with a <see cref="Pen"/> object.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public IDashStyle DashStyle
|
|
|
|
|
+ {
|
|
|
|
|
+ get => GetValue(DashStyleProperty);
|
|
|
|
|
+ set => SetValue(DashStyleProperty, value);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /// <summary>
|
|
|
|
|
+ /// Gets or sets the type of shape to use on both ends of a line.
|
|
|
|
|
+ /// </summary>
|
|
|
|
|
+ public PenLineCap LineCap
|
|
|
|
|
+ {
|
|
|
|
|
+ get => GetValue(LineCapProperty);
|
|
|
|
|
+ set => SetValue(LineCapProperty, value);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// Gets the brush used to draw the stroke.
|
|
|
|
|
|
|
+ /// Gets or sets the join style for the ends of two consecutive lines drawn with this
|
|
|
|
|
+ /// <see cref="Pen"/>.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
- public IBrush Brush { get; }
|
|
|
|
|
|
|
+ public PenLineJoin LineJoin
|
|
|
|
|
+ {
|
|
|
|
|
+ get => GetValue(LineJoinProperty);
|
|
|
|
|
+ set => SetValue(LineJoinProperty, value);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// Gets the stroke thickness.
|
|
|
|
|
|
|
+ /// Gets or sets the limit of the thickness of the join on a mitered corner.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
- public double Thickness { get; }
|
|
|
|
|
|
|
+ public double MiterLimit
|
|
|
|
|
+ {
|
|
|
|
|
+ get => GetValue(MiterLimitProperty);
|
|
|
|
|
+ set => SetValue(MiterLimitProperty, value);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// Specifies the style of dashed lines drawn with a <see cref="Pen"/> object.
|
|
|
|
|
|
|
+ /// Raised when the pen changes.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
- public DashStyle DashStyle { get; }
|
|
|
|
|
|
|
+ public event EventHandler Invalidated;
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// Specifies the type of graphic shape to use on both ends of a line.
|
|
|
|
|
|
|
+ /// Creates an immutable clone of the brush.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
- public PenLineCap LineCap { get; }
|
|
|
|
|
|
|
+ /// <returns>The immutable clone.</returns>
|
|
|
|
|
+ public ImmutablePen ToImmutable()
|
|
|
|
|
+ {
|
|
|
|
|
+ return new ImmutablePen(
|
|
|
|
|
+ Brush?.ToImmutable(),
|
|
|
|
|
+ Thickness,
|
|
|
|
|
+ DashStyle?.ToImmutable(),
|
|
|
|
|
+ LineCap,
|
|
|
|
|
+ LineJoin,
|
|
|
|
|
+ MiterLimit);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// Specifies how to join consecutive line or curve segments in a <see cref="PathFigure"/> (subpath) contained in a <see cref="PathGeometry"/> object.
|
|
|
|
|
|
|
+ /// Marks a property as affecting the pen's visual representation.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
- public PenLineJoin LineJoin { get; }
|
|
|
|
|
|
|
+ /// <param name="properties">The properties.</param>
|
|
|
|
|
+ /// <remarks>
|
|
|
|
|
+ /// After a call to this method in a pen's static constructor, any change to the
|
|
|
|
|
+ /// property will cause the <see cref="Invalidated"/> event to be raised on the pen.
|
|
|
|
|
+ /// </remarks>
|
|
|
|
|
+ protected static void AffectsRender<T>(params AvaloniaProperty[] properties)
|
|
|
|
|
+ where T : Pen
|
|
|
|
|
+ {
|
|
|
|
|
+ void Invalidate(AvaloniaPropertyChangedEventArgs e)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (e.Sender is T sender)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (e.OldValue is IAffectsRender oldValue)
|
|
|
|
|
+ {
|
|
|
|
|
+ WeakEventHandlerManager.Unsubscribe<EventArgs, T>(
|
|
|
|
|
+ oldValue,
|
|
|
|
|
+ nameof(oldValue.Invalidated),
|
|
|
|
|
+ sender.AffectsRenderInvalidated);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (e.NewValue is IAffectsRender newValue)
|
|
|
|
|
+ {
|
|
|
|
|
+ WeakEventHandlerManager.Subscribe<IAffectsRender, EventArgs, T>(
|
|
|
|
|
+ newValue,
|
|
|
|
|
+ nameof(newValue.Invalidated),
|
|
|
|
|
+ sender.AffectsRenderInvalidated);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sender.RaiseInvalidated(EventArgs.Empty);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ foreach (var property in properties)
|
|
|
|
|
+ {
|
|
|
|
|
+ property.Changed.Subscribe(Invalidate);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
- /// The limit on the ratio of the miter length to half this pen's Thickness.
|
|
|
|
|
|
|
+ /// Raises the <see cref="Invalidated"/> event.
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
- public double MiterLimit { get; }
|
|
|
|
|
|
|
+ /// <param name="e">The event args.</param>
|
|
|
|
|
+ protected void RaiseInvalidated(EventArgs e) => Invalidated?.Invoke(this, e);
|
|
|
|
|
+
|
|
|
|
|
+ private void AffectsRenderInvalidated(object sender, EventArgs e) => RaiseInvalidated(EventArgs.Empty);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|