Browse Source

Merge pull request #6836 from RomanSoloweow/master

Border StrokeDashArray
pull/7094/head
GMIKE 4 years ago
committed by GitHub
parent
commit
621bb5688d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 74
      src/Avalonia.Controls/Border.cs
  2. 52
      src/Avalonia.Controls/Utils/BorderRenderHelper.cs

74
src/Avalonia.Controls/Border.cs

@ -1,3 +1,5 @@
using Avalonia.Collections;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Utils;
using Avalonia.Layout;
using Avalonia.Media;
@ -41,7 +43,31 @@ namespace Avalonia.Controls
/// </summary>
public static readonly StyledProperty<BoxShadows> BoxShadowProperty =
AvaloniaProperty.Register<Border, BoxShadows>(nameof(BoxShadow));
/// <summary>
/// Defines the <see cref="BorderDashOffset"/> property.
/// </summary>
public static readonly StyledProperty<double> BorderDashOffsetProperty =
AvaloniaProperty.Register<Border, double>(nameof(BorderDashOffset));
/// <summary>
/// Defines the <see cref="BorderDashArray"/> property.
/// </summary>
public static readonly StyledProperty<AvaloniaList<double>?> BorderDashArrayProperty =
AvaloniaProperty.Register<Border, AvaloniaList<double>?>(nameof(BorderDashArray));
/// <summary>
/// Defines the <see cref="BorderLineCap"/> property.
/// </summary>
public static readonly StyledProperty<PenLineCap> BorderLineCapProperty =
AvaloniaProperty.Register<Border, PenLineCap>(nameof(BorderLineCap), PenLineCap.Flat);
/// <summary>
/// Defines the <see cref="BorderLineJoin"/> property.
/// </summary>
public static readonly StyledProperty<PenLineJoin> BorderLineJoinProperty =
AvaloniaProperty.Register<Border, PenLineJoin>(nameof(BorderLineJoin), PenLineJoin.Miter);
private readonly BorderRenderHelper _borderRenderHelper = new BorderRenderHelper();
/// <summary>
@ -54,6 +80,10 @@ namespace Avalonia.Controls
BorderBrushProperty,
BorderThicknessProperty,
CornerRadiusProperty,
BorderDashArrayProperty,
BorderLineCapProperty,
BorderLineJoinProperty,
BorderDashOffsetProperty,
BoxShadowProperty);
AffectsMeasure<Border>(BorderThicknessProperty);
}
@ -76,6 +106,15 @@ namespace Avalonia.Controls
set { SetValue(BorderBrushProperty, value); }
}
/// <summary>
/// Gets or sets a collection of <see cref="double"/> values that indicate the pattern of dashes and gaps that is used to outline shapes.
/// </summary>
public AvaloniaList<double>? BorderDashArray
{
get { return GetValue(BorderDashArrayProperty); }
set { SetValue(BorderDashArrayProperty, value); }
}
/// <summary>
/// Gets or sets the thickness of the border.
/// </summary>
@ -85,6 +124,33 @@ namespace Avalonia.Controls
set { SetValue(BorderThicknessProperty, value); }
}
/// <summary>
/// Gets or sets a value that specifies the distance within the dash pattern where a dash begins.
/// </summary>
public double BorderDashOffset
{
get { return GetValue(BorderDashOffsetProperty); }
set { SetValue(BorderDashOffsetProperty, value); }
}
/// <summary>
/// Gets or sets a <see cref="PenLineCap"/> enumeration value that describes the shape at the ends of a line.
/// </summary>
public PenLineCap BorderLineCap
{
get { return GetValue(BorderLineCapProperty); }
set { SetValue(BorderLineCapProperty, value); }
}
/// <summary>
/// Gets or sets a <see cref="PenLineJoin"/> enumeration value that specifies the type of join that is used at the vertices of a Shape.
/// </summary>
public PenLineJoin BorderLineJoin
{
get { return GetValue(BorderLineJoinProperty); }
set { SetValue(BorderLineJoinProperty, value); }
}
/// <summary>
/// Gets or sets the radius of the border rounded corners.
/// </summary>
@ -93,7 +159,7 @@ namespace Avalonia.Controls
get { return GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Gets or sets the box shadow effect parameters
/// </summary>
@ -102,7 +168,7 @@ namespace Avalonia.Controls
get => GetValue(BoxShadowProperty);
set => SetValue(BoxShadowProperty, value);
}
/// <summary>
/// Renders the control.
/// </summary>
@ -110,7 +176,7 @@ namespace Avalonia.Controls
public override void Render(DrawingContext context)
{
_borderRenderHelper.Render(context, Bounds.Size, BorderThickness, CornerRadius, Background, BorderBrush,
BoxShadow);
BoxShadow, BorderDashOffset, BorderLineCap, BorderLineJoin, BorderDashArray);
}
/// <summary>

52
src/Avalonia.Controls/Utils/BorderRenderHelper.cs

@ -1,8 +1,10 @@
using System;
using Avalonia.Collections;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.Utilities;
using JetBrains.Annotations;
namespace Avalonia.Controls.Utils
{
@ -15,8 +17,13 @@ namespace Avalonia.Controls.Utils
private Size _size;
private Thickness _borderThickness;
private CornerRadius _cornerRadius;
private AvaloniaList<double> _borderDashArray;
private double _borderDashOffset;
private PenLineCap _borderLineCap;
private PenLineJoin _borderJoin;
private bool _initialized;
void Update(Size finalSize, Thickness borderThickness, CornerRadius cornerRadius)
{
_backendSupportsIndividualCorners ??= AvaloniaLocator.Current.GetService<IPlatformRenderInterface>()
@ -60,7 +67,8 @@ namespace Avalonia.Controls.Utils
if (boundRect.Width != 0 && innerRect.Height != 0)
{
var borderGeometryKeypoints = new BorderGeometryKeypoints(boundRect, borderThickness, cornerRadius, false);
var borderGeometryKeypoints =
new BorderGeometryKeypoints(boundRect, borderThickness, cornerRadius, false);
var borderGeometry = new StreamGeometry();
using (var ctx = borderGeometry.Open())
@ -84,17 +92,22 @@ namespace Avalonia.Controls.Utils
public void Render(DrawingContext context,
Size finalSize, Thickness borderThickness, CornerRadius cornerRadius,
IBrush background, IBrush borderBrush, BoxShadows boxShadows)
IBrush background, IBrush borderBrush, BoxShadows boxShadows, double borderDashOffset = 0,
PenLineCap borderLineCap = PenLineCap.Flat, PenLineJoin borderLineJoin = PenLineJoin.Miter,
AvaloniaList<double> borderDashArray = null)
{
if (_size != finalSize
|| _borderThickness != borderThickness
|| _cornerRadius != cornerRadius
|| !_initialized)
Update(finalSize, borderThickness, cornerRadius);
RenderCore(context, background, borderBrush, boxShadows);
RenderCore(context, background, borderBrush, boxShadows, borderDashOffset, borderLineCap, borderLineJoin,
borderDashArray);
}
void RenderCore(DrawingContext context, IBrush background, IBrush borderBrush, BoxShadows boxShadows)
void RenderCore(DrawingContext context, IBrush background, IBrush borderBrush, BoxShadows boxShadows,
double borderDashOffset, PenLineCap borderLineCap, PenLineJoin borderLineJoin,
AvaloniaList<double> borderDashArray)
{
if (_useComplexRendering)
{
@ -115,11 +128,25 @@ namespace Avalonia.Controls.Utils
var borderThickness = _borderThickness.Top;
IPen pen = null;
ImmutableDashStyle? dashStyle = null;
if (borderDashArray != null && borderDashArray.Count > 0)
{
dashStyle = new ImmutableDashStyle(borderDashArray, borderDashOffset);
}
if (borderBrush != null && borderThickness > 0)
{
pen = new ImmutablePen(borderBrush.ToImmutable(), borderThickness);
pen = new ImmutablePen(
borderBrush.ToImmutable(),
borderThickness,
dashStyle,
borderLineCap,
borderLineJoin);
}
var rect = new Rect(_size);
if (!MathUtilities.IsZero(borderThickness))
rect = rect.Deflate(borderThickness * 0.5);
@ -130,7 +157,8 @@ namespace Avalonia.Controls.Utils
}
}
private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderGeometryKeypoints keypoints)
private static void CreateGeometry(StreamGeometryContext context, Rect boundRect,
BorderGeometryKeypoints keypoints)
{
context.BeginFigure(keypoints.TopLeft, true);
@ -184,7 +212,8 @@ namespace Avalonia.Controls.Utils
private class BorderGeometryKeypoints
{
internal BorderGeometryKeypoints(Rect boundRect, Thickness borderThickness, CornerRadius cornerRadius, bool inner)
internal BorderGeometryKeypoints(Rect boundRect, Thickness borderThickness, CornerRadius cornerRadius,
bool inner)
{
var left = 0.5 * borderThickness.Left;
var top = 0.5 * borderThickness.Top;
@ -206,10 +235,13 @@ namespace Avalonia.Controls.Utils
topLeftX = Math.Max(0, cornerRadius.TopLeft - left) + boundRect.TopLeft.X;
topRightX = boundRect.Width - Math.Max(0, cornerRadius.TopRight - top) + boundRect.TopLeft.X;
rightTopY = Math.Max(0, cornerRadius.TopRight - right) + boundRect.TopLeft.Y;
rightBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomRight - bottom) + boundRect.TopLeft.Y;
bottomRightX = boundRect.Width - Math.Max(0, cornerRadius.BottomRight - right) + boundRect.TopLeft.X;
rightBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomRight - bottom) +
boundRect.TopLeft.Y;
bottomRightX = boundRect.Width - Math.Max(0, cornerRadius.BottomRight - right) +
boundRect.TopLeft.X;
bottomLeftX = Math.Max(0, cornerRadius.BottomLeft - left) + boundRect.TopLeft.X;
leftBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomLeft - bottom) + boundRect.TopLeft.Y;
leftBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomLeft - bottom) +
boundRect.TopLeft.Y;
}
else
{

Loading…
Cancel
Save