|
|
@@ -26,17 +26,17 @@ namespace Avalonia.Controls.Utils
|
|
|
|
|
|
var boundRect = new Rect(finalSize);
|
|
|
var innerRect = boundRect.Deflate(borderThickness);
|
|
|
- var innerCoordinates = GeometryCoordinates.CreateBackgroundCoordinates(cornerRadius, borderThickness);
|
|
|
-
|
|
|
+ BorderGeometryKeypoints backgroundKeypoints = null;
|
|
|
StreamGeometry backgroundGeometry = null;
|
|
|
|
|
|
if (innerRect.Width != 0 && innerRect.Height != 0)
|
|
|
{
|
|
|
backgroundGeometry = new StreamGeometry();
|
|
|
+ backgroundKeypoints = new BorderGeometryKeypoints(innerRect, borderThickness, cornerRadius, true);
|
|
|
|
|
|
using (var ctx = backgroundGeometry.Open())
|
|
|
{
|
|
|
- CreateGeometry(ctx, innerRect, innerCoordinates);
|
|
|
+ CreateGeometry(ctx, innerRect, backgroundKeypoints);
|
|
|
}
|
|
|
|
|
|
_backgroundGeometryCache = backgroundGeometry;
|
|
|
@@ -48,16 +48,16 @@ namespace Avalonia.Controls.Utils
|
|
|
|
|
|
if (boundRect.Width != 0 && innerRect.Height != 0)
|
|
|
{
|
|
|
- var outerCoordinates = GeometryCoordinates.CreateBorderCoordinates(cornerRadius, borderThickness);
|
|
|
+ var borderGeometryKeypoints = new BorderGeometryKeypoints(boundRect, borderThickness, cornerRadius, false);
|
|
|
var borderGeometry = new StreamGeometry();
|
|
|
|
|
|
using (var ctx = borderGeometry.Open())
|
|
|
{
|
|
|
- CreateGeometry(ctx, boundRect, outerCoordinates);
|
|
|
+ CreateGeometry(ctx, boundRect, borderGeometryKeypoints);
|
|
|
|
|
|
if (backgroundGeometry != null)
|
|
|
{
|
|
|
- CreateGeometry(ctx, innerRect, innerCoordinates);
|
|
|
+ CreateGeometry(ctx, innerRect, backgroundKeypoints);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -104,188 +104,156 @@ namespace Avalonia.Controls.Utils
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, GeometryCoordinates geometryCoordinates)
|
|
|
- {
|
|
|
- var topLeft = new Point(geometryCoordinates.LeftTop, 0);
|
|
|
- var topRight = new Point(boundRect.Width - geometryCoordinates.RightTop, 0);
|
|
|
- var rightTop = new Point(boundRect.Width, geometryCoordinates.TopRight);
|
|
|
- var rightBottom = new Point(boundRect.Width, boundRect.Height - geometryCoordinates.BottomRight);
|
|
|
- var bottomRight = new Point(boundRect.Width - geometryCoordinates.RightBottom, boundRect.Height);
|
|
|
- var bottomLeft = new Point(geometryCoordinates.LeftBottom, boundRect.Height);
|
|
|
- var leftBottom = new Point(0, boundRect.Height - geometryCoordinates.BottomLeft);
|
|
|
- var leftTop = new Point(0, geometryCoordinates.TopLeft);
|
|
|
-
|
|
|
- if (topLeft.X > topRight.X)
|
|
|
+ private class BorderGeometryKeypoints
|
|
|
+ {
|
|
|
+ internal BorderGeometryKeypoints(Rect boundRect, Thickness borderThickness, CornerRadius cornerRadius, bool inner)
|
|
|
{
|
|
|
- var scaledX = geometryCoordinates.LeftTop / (geometryCoordinates.LeftTop + geometryCoordinates.RightTop) * boundRect.Width;
|
|
|
- topLeft = new Point(scaledX, topLeft.Y);
|
|
|
- topRight = new Point(scaledX, topRight.Y);
|
|
|
- }
|
|
|
+ var left = 0.5 * borderThickness.Left;
|
|
|
+ var top = 0.5 * borderThickness.Top;
|
|
|
+ var right = 0.5 * borderThickness.Right;
|
|
|
+ var bottom = 0.5 * borderThickness.Bottom;
|
|
|
|
|
|
- if (rightTop.Y > rightBottom.Y)
|
|
|
- {
|
|
|
- var scaledY = geometryCoordinates.TopRight / (geometryCoordinates.TopRight + geometryCoordinates.BottomRight) * boundRect.Height;
|
|
|
- rightTop = new Point(rightTop.X, scaledY);
|
|
|
- rightBottom = new Point(rightBottom.X, scaledY);
|
|
|
- }
|
|
|
+ double leftTopY;
|
|
|
+ double topLeftX;
|
|
|
+ double topRightX;
|
|
|
+ double rightTopY;
|
|
|
+ double rightBottomY;
|
|
|
+ double bottomRightX;
|
|
|
+ double bottomLeftX;
|
|
|
+ double leftBottomY;
|
|
|
|
|
|
- if (bottomRight.X < bottomLeft.X)
|
|
|
- {
|
|
|
- var scaledX = geometryCoordinates.LeftBottom / (geometryCoordinates.LeftBottom + geometryCoordinates.RightBottom) * boundRect.Width;
|
|
|
- bottomRight = new Point(scaledX, bottomRight.Y);
|
|
|
- bottomLeft = new Point(scaledX, bottomLeft.Y);
|
|
|
- }
|
|
|
+ if (inner)
|
|
|
+ {
|
|
|
+ leftTopY = Math.Max(0, cornerRadius.TopLeft - top) + boundRect.TopLeft.Y;
|
|
|
+ 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;
|
|
|
+ bottomLeftX = Math.Max(0, cornerRadius.BottomLeft - left) + boundRect.TopLeft.X;
|
|
|
+ leftBottomY = boundRect.Height - Math.Max(0, cornerRadius.BottomLeft - bottom) + boundRect.TopLeft.Y;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ leftTopY = cornerRadius.TopLeft + top + boundRect.TopLeft.Y;
|
|
|
+ topLeftX = cornerRadius.TopLeft + left + boundRect.TopLeft.X;
|
|
|
+ topRightX = boundRect.Width - (cornerRadius.TopRight + right) + boundRect.TopLeft.X;
|
|
|
+ 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;
|
|
|
+ leftBottomY = boundRect.Height - (cornerRadius.BottomLeft + bottom) + 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 bottomLeftY = boundRect.Height + boundRect.TopLeft.Y;
|
|
|
+ var leftBottomX = boundRect.TopLeft.X;
|
|
|
+
|
|
|
+ LeftTop = new Point(leftTopX, leftTopY);
|
|
|
+ TopLeft = new Point(topLeftX, topLeftY);
|
|
|
+ TopRight = new Point(topRightX, topRightY);
|
|
|
+ RightTop = new Point(rightTopX, rightTopY);
|
|
|
+ RightBottom = new Point(rightBottomX, rightBottomY);
|
|
|
+ BottomRight = new Point(bottomRightX, bottomRightY);
|
|
|
+ BottomLeft = new Point(bottomLeftX, bottomLeftY);
|
|
|
+ LeftBottom = new Point(leftBottomX, leftBottomY);
|
|
|
+
|
|
|
+ //Fix overlap
|
|
|
+ if (TopLeft.X > TopRight.X)
|
|
|
+ {
|
|
|
+ var scaledX = topLeftX / (topLeftX + topRightX) * boundRect.Width;
|
|
|
+ TopLeft = new Point(scaledX, TopLeft.Y);
|
|
|
+ TopRight = new Point(scaledX, TopRight.Y);
|
|
|
+ }
|
|
|
|
|
|
- if (leftBottom.Y < leftTop.Y)
|
|
|
- {
|
|
|
- var scaledY = geometryCoordinates.TopLeft / (geometryCoordinates.TopLeft + geometryCoordinates.BottomLeft) * boundRect.Height;
|
|
|
- leftBottom = new Point(leftBottom.X, scaledY);
|
|
|
- leftTop = new Point(leftTop.X, scaledY);
|
|
|
+ if (RightTop.Y > RightBottom.Y)
|
|
|
+ {
|
|
|
+ var scaledY = rightBottomY / (rightTopY + rightBottomY) * boundRect.Height;
|
|
|
+ RightTop = new Point(RightTop.X, scaledY);
|
|
|
+ RightBottom = new Point(RightBottom.X, scaledY);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (BottomRight.X < BottomLeft.X)
|
|
|
+ {
|
|
|
+ var scaledX = bottomLeftX / (bottomLeftX + bottomRightX) * boundRect.Width;
|
|
|
+ BottomRight = new Point(scaledX, BottomRight.Y);
|
|
|
+ BottomLeft = new Point(scaledX, BottomLeft.Y);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (LeftBottom.Y < LeftTop.Y)
|
|
|
+ {
|
|
|
+ var scaledY = leftTopY / (leftTopY + leftBottomY) * boundRect.Height;
|
|
|
+ LeftBottom = new Point(LeftBottom.X, scaledY);
|
|
|
+ LeftTop = new Point(LeftTop.X, scaledY);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- var offset = new Vector(boundRect.TopLeft.X, boundRect.TopLeft.Y);
|
|
|
- topLeft += offset;
|
|
|
- topRight += offset;
|
|
|
- rightTop += offset;
|
|
|
- rightBottom += offset;
|
|
|
- bottomRight += offset;
|
|
|
- bottomLeft += offset;
|
|
|
- leftBottom += offset;
|
|
|
- leftTop += offset;
|
|
|
+ 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; }
|
|
|
+ }
|
|
|
|
|
|
- context.BeginFigure(topLeft, true);
|
|
|
+ private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderGeometryKeypoints keypoints)
|
|
|
+ {
|
|
|
+ context.BeginFigure(keypoints.TopLeft, true);
|
|
|
|
|
|
//Top
|
|
|
- context.LineTo(topRight);
|
|
|
+ context.LineTo(keypoints.TopRight);
|
|
|
|
|
|
//TopRight corner
|
|
|
- var radiusX = boundRect.TopRight.X - topRight.X;
|
|
|
- var radiusY = rightTop.Y - boundRect.TopRight.Y;
|
|
|
+ var radiusX = boundRect.TopRight.X - keypoints.TopRight.X;
|
|
|
+ var radiusY = keypoints.RightTop.Y - boundRect.TopRight.Y;
|
|
|
if (radiusX != 0 || radiusY != 0)
|
|
|
{
|
|
|
- context.ArcTo(rightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise);
|
|
|
+ context.ArcTo(keypoints.RightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise);
|
|
|
}
|
|
|
|
|
|
//Right
|
|
|
- context.LineTo(rightBottom);
|
|
|
+ context.LineTo(keypoints.RightBottom);
|
|
|
|
|
|
//BottomRight corner
|
|
|
- radiusX = boundRect.BottomRight.X - bottomRight.X;
|
|
|
- radiusY = boundRect.BottomRight.Y - rightBottom.Y;
|
|
|
+ radiusX = boundRect.BottomRight.X - keypoints.BottomRight.X;
|
|
|
+ radiusY = boundRect.BottomRight.Y - keypoints.RightBottom.Y;
|
|
|
if (radiusX != 0 || radiusY != 0)
|
|
|
{
|
|
|
- context.ArcTo(bottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
|
|
|
+ context.ArcTo(keypoints.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
|
|
|
}
|
|
|
|
|
|
//Bottom
|
|
|
- context.LineTo(bottomLeft);
|
|
|
+ context.LineTo(keypoints.BottomLeft);
|
|
|
|
|
|
//BottomLeft corner
|
|
|
- radiusX = bottomLeft.X - boundRect.BottomLeft.X;
|
|
|
- radiusY = boundRect.BottomLeft.Y - leftBottom.Y;
|
|
|
+ radiusX = keypoints.BottomLeft.X - boundRect.BottomLeft.X;
|
|
|
+ radiusY = boundRect.BottomLeft.Y - keypoints.LeftBottom.Y;
|
|
|
if (radiusX != 0 || radiusY != 0)
|
|
|
{
|
|
|
- context.ArcTo(leftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
|
|
|
+ context.ArcTo(keypoints.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
|
|
|
}
|
|
|
|
|
|
//Left
|
|
|
- context.LineTo(leftTop);
|
|
|
+ context.LineTo(keypoints.LeftTop);
|
|
|
|
|
|
//TopLeft corner
|
|
|
- radiusX = topLeft.X - boundRect.TopLeft.X;
|
|
|
- radiusY = leftTop.Y - boundRect.TopLeft.Y;
|
|
|
+ radiusX = keypoints.TopLeft.X - boundRect.TopLeft.X;
|
|
|
+ radiusY = keypoints.LeftTop.Y - boundRect.TopLeft.Y;
|
|
|
|
|
|
if (radiusX != 0 || radiusY != 0)
|
|
|
{
|
|
|
- context.ArcTo(topLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
|
|
|
+ context.ArcTo(keypoints.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
|
|
|
}
|
|
|
|
|
|
context.EndFigure(true);
|
|
|
}
|
|
|
-
|
|
|
- private struct GeometryCoordinates
|
|
|
- {
|
|
|
- internal static GeometryCoordinates CreateBorderCoordinates(CornerRadius cornerRadius, Thickness borderThickness)
|
|
|
- {
|
|
|
- var left = 0.5 * borderThickness.Left;
|
|
|
- var top = 0.5 * borderThickness.Top;
|
|
|
- var right = 0.5 * borderThickness.Right;
|
|
|
- var bottom = 0.5 * borderThickness.Bottom;
|
|
|
-
|
|
|
- var leftTop = 0.0;
|
|
|
- var topLeft = 0.0;
|
|
|
- if (cornerRadius.TopLeft != 0)
|
|
|
- {
|
|
|
- leftTop = cornerRadius.TopLeft + left;
|
|
|
- topLeft = cornerRadius.TopLeft + top;
|
|
|
- }
|
|
|
-
|
|
|
- var topRight = 0.0;
|
|
|
- var rightTop = 0.0;
|
|
|
- if (cornerRadius.TopRight != 0)
|
|
|
- {
|
|
|
- topRight = cornerRadius.TopRight + top;
|
|
|
- rightTop = cornerRadius.TopRight + right;
|
|
|
- }
|
|
|
-
|
|
|
- var rightBottom = 0.0;
|
|
|
- var bottomRight = 0.0;
|
|
|
- if (cornerRadius.BottomRight != 0)
|
|
|
- {
|
|
|
- rightBottom = cornerRadius.BottomRight + right;
|
|
|
- bottomRight = cornerRadius.BottomRight + bottom;
|
|
|
- }
|
|
|
-
|
|
|
- var bottomLeft = 0.0;
|
|
|
- var leftBottom = 0.0;
|
|
|
- if (cornerRadius.BottomLeft != 0)
|
|
|
- {
|
|
|
- bottomLeft = cornerRadius.BottomLeft + bottom;
|
|
|
- leftBottom = cornerRadius.BottomLeft + left;
|
|
|
- }
|
|
|
-
|
|
|
- return new GeometryCoordinates
|
|
|
- {
|
|
|
- LeftTop = leftTop,
|
|
|
- TopLeft = topLeft,
|
|
|
- TopRight = topRight,
|
|
|
- RightTop = rightTop,
|
|
|
- RightBottom = rightBottom,
|
|
|
- BottomRight = bottomRight,
|
|
|
- BottomLeft = bottomLeft,
|
|
|
- LeftBottom = leftBottom,
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- internal static GeometryCoordinates CreateBackgroundCoordinates(CornerRadius cornerRadius, Thickness borderThickness)
|
|
|
- {
|
|
|
- var left = 0.5 * borderThickness.Left;
|
|
|
- var top = 0.5 * borderThickness.Top;
|
|
|
- var right = 0.5 * borderThickness.Right;
|
|
|
- var bottom = 0.5 * borderThickness.Bottom;
|
|
|
-
|
|
|
- return new GeometryCoordinates
|
|
|
- {
|
|
|
- LeftTop = Math.Max(0, cornerRadius.TopLeft - left),
|
|
|
- TopLeft = Math.Max(0, cornerRadius.TopLeft - top),
|
|
|
- TopRight = Math.Max(0, cornerRadius.TopRight - top),
|
|
|
- RightTop = Math.Max(0, cornerRadius.TopRight - right),
|
|
|
- RightBottom = Math.Max(0, cornerRadius.BottomRight - right),
|
|
|
- BottomRight = Math.Max(0, cornerRadius.BottomRight - bottom),
|
|
|
- BottomLeft = Math.Max(0, cornerRadius.BottomLeft - bottom),
|
|
|
- LeftBottom = Math.Max(0, cornerRadius.BottomLeft - left),
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- internal double LeftTop { get; private set; }
|
|
|
- internal double TopLeft { get; private set; }
|
|
|
- internal double TopRight { get; private set; }
|
|
|
- internal double RightTop { get; private set; }
|
|
|
- internal double RightBottom { get; private set; }
|
|
|
- internal double BottomRight { get; private set; }
|
|
|
- internal double BottomLeft { get; private set; }
|
|
|
- internal double LeftBottom { get; private set; }
|
|
|
- }
|
|
|
-
|
|
|
}
|
|
|
}
|