diff --git a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs index 0fd6593fbe..62867f1d22 100644 --- a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs +++ b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs @@ -88,24 +88,79 @@ namespace Avalonia.Controls.Utils } else { - var borderThickness = borders.Left; - var cornerRadius = (float)radii.TopLeft; - var rect = new Rect(size); + var borderThickness = borders.Top; + var cornerRadius = (float)Math.Max(0, radii.TopLeft - borderThickness); if (background != null) { - context.FillRectangle(background, rect.Deflate(borders), cornerRadius); + var innerRect = new Rect(new Point(borders.Left, borders.Top), new Point(size.Width - borders.Right, size.Height - borders.Bottom)); + context.DrawRectangle(new Pen(background, borderThickness), innerRect, cornerRadius); + context.FillRectangle(background, innerRect, cornerRadius); } if (borderBrush != null && borderThickness > 0) { - context.DrawRectangle(new Pen(borderBrush, borderThickness), rect.Deflate(borderThickness), cornerRadius); + var top = borderThickness * 0.5; + var outerRect = new Rect(new Point(top, top), new Point(size.Width - top, size.Height - top)); + context.DrawRectangle(new Pen(borderBrush, borderThickness), outerRect, (float)radii.TopLeft); } } + } + + private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderGeometryKeypoints keypoints) + { + context.BeginFigure(keypoints.TopLeft, true); + + // Top + context.LineTo(keypoints.TopRight); + + // TopRight corner + var radiusX = boundRect.TopRight.X - keypoints.TopRight.X; + var radiusY = keypoints.RightTop.Y - boundRect.TopRight.Y; + if (radiusX != 0 || radiusY != 0) + { + context.ArcTo(keypoints.RightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise); + } + + // Right + context.LineTo(keypoints.RightBottom); + + // BottomRight corner + radiusX = boundRect.BottomRight.X - keypoints.BottomRight.X; + radiusY = boundRect.BottomRight.Y - keypoints.RightBottom.Y; + if (radiusX != 0 || radiusY != 0) + { + context.ArcTo(keypoints.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise); + } + + // Bottom + context.LineTo(keypoints.BottomLeft); + + // BottomLeft corner + radiusX = keypoints.BottomLeft.X - boundRect.BottomLeft.X; + radiusY = boundRect.BottomLeft.Y - keypoints.LeftBottom.Y; + if (radiusX != 0 || radiusY != 0) + { + context.ArcTo(keypoints.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise); + } + + // Left + context.LineTo(keypoints.LeftTop); + + // TopLeft corner + radiusX = keypoints.TopLeft.X - boundRect.TopLeft.X; + radiusY = keypoints.LeftTop.Y - boundRect.TopLeft.Y; + + if (radiusX != 0 || radiusY != 0) + { + context.ArcTo(keypoints.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise); + } + + context.EndFigure(true); } private class BorderGeometryKeypoints - { + { internal BorderGeometryKeypoints(Rect boundRect, Thickness borderThickness, CornerRadius cornerRadius, bool inner) { var left = 0.5 * borderThickness.Left; @@ -135,25 +190,24 @@ namespace Avalonia.Controls.Utils } else { - leftTopY = cornerRadius.TopLeft + top + boundRect.TopLeft.Y; - topLeftX = cornerRadius.TopLeft + left + boundRect.TopLeft.X; + topLeftX = cornerRadius.TopLeft + left + boundRect.TopLeft.X; topRightX = boundRect.Width - (cornerRadius.TopRight + right) + boundRect.TopLeft.X; - rightTopY = cornerRadius.TopRight + top + boundRect.TopLeft.Y; + rightTopY = cornerRadius.TopRight + top + boundRect.TopLeft.Y; rightBottomY = boundRect.Height - (cornerRadius.BottomRight + bottom) + boundRect.TopLeft.Y; - bottomRightX = boundRect.Width - (cornerRadius.BottomRight + right) + boundRect.TopLeft.X; - bottomLeftX = cornerRadius.BottomLeft + left + boundRect.TopLeft.X; + bottomRightX = boundRect.Width - (cornerRadius.BottomRight + right) + boundRect.TopLeft.X; + bottomLeftX = cornerRadius.BottomLeft + left + boundRect.TopLeft.X; leftBottomY = boundRect.Height - (cornerRadius.BottomLeft + bottom) + boundRect.TopLeft.Y; - } + } - var leftTopX = boundRect.TopLeft.X; - var topLeftY = boundRect.TopLeft.Y; + var leftTopX = boundRect.TopLeft.X; + var topLeftY = boundRect.TopLeft.Y; var topRightY = boundRect.TopLeft.Y; - var rightTopX = boundRect.Width + boundRect.TopLeft.X; - var rightBottomX = boundRect.Width + boundRect.TopLeft.X; - var bottomRightY = boundRect.Height + boundRect.TopLeft.Y; + var rightTopX = boundRect.Width + boundRect.TopLeft.X; + var rightBottomX = boundRect.Width + boundRect.TopLeft.X; + var bottomRightY = boundRect.Height + boundRect.TopLeft.Y; var bottomLeftY = boundRect.Height + boundRect.TopLeft.Y; - var leftBottomX = boundRect.TopLeft.X; + var leftBottomX = boundRect.TopLeft.X; LeftTop = new Point(leftTopX, leftTopY); TopLeft = new Point(topLeftX, topLeftY); @@ -164,7 +218,7 @@ namespace Avalonia.Controls.Utils BottomLeft = new Point(bottomLeftX, bottomLeftY); LeftBottom = new Point(leftBottomX, leftBottomY); - //Fix overlap + // Fix overlap if (TopLeft.X > TopRight.X) { var scaledX = topLeftX / (topLeftX + topRightX) * boundRect.Width; @@ -194,66 +248,21 @@ namespace Avalonia.Controls.Utils } } - internal Point LeftTop { get; private set; } - internal Point TopLeft { get; private set; } - internal Point TopRight { get; private set; } - internal Point RightTop { get; private set; } - internal Point RightBottom { get; private set; } - internal Point BottomRight { get; private set; } - internal Point BottomLeft { get; private set; } - internal Point LeftBottom { get; private set; } - } + internal Point LeftTop { get; } - private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderGeometryKeypoints keypoints) - { - context.BeginFigure(keypoints.TopLeft, true); + internal Point TopLeft { get; } - //Top - context.LineTo(keypoints.TopRight); + internal Point TopRight { get; } - //TopRight corner - var radiusX = boundRect.TopRight.X - keypoints.TopRight.X; - var radiusY = keypoints.RightTop.Y - boundRect.TopRight.Y; - if (radiusX != 0 || radiusY != 0) - { - context.ArcTo(keypoints.RightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise); - } + internal Point RightTop { get; } - //Right - context.LineTo(keypoints.RightBottom); + internal Point RightBottom { get; } - //BottomRight corner - radiusX = boundRect.BottomRight.X - keypoints.BottomRight.X; - radiusY = boundRect.BottomRight.Y - keypoints.RightBottom.Y; - if (radiusX != 0 || radiusY != 0) - { - context.ArcTo(keypoints.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise); - } - - //Bottom - context.LineTo(keypoints.BottomLeft); - - //BottomLeft corner - radiusX = keypoints.BottomLeft.X - boundRect.BottomLeft.X; - radiusY = boundRect.BottomLeft.Y - keypoints.LeftBottom.Y; - if (radiusX != 0 || radiusY != 0) - { - context.ArcTo(keypoints.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise); - } + internal Point BottomRight { get; } - //Left - context.LineTo(keypoints.LeftTop); - - //TopLeft corner - radiusX = keypoints.TopLeft.X - boundRect.TopLeft.X; - radiusY = keypoints.LeftTop.Y - boundRect.TopLeft.Y; - - if (radiusX != 0 || radiusY != 0) - { - context.ArcTo(keypoints.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise); - } + internal Point BottomLeft { get; } - context.EndFigure(true); + internal Point LeftBottom { get; } } } }