Browse Source

Cleanup BorderRenderHelper

Name fix in ContentPresenter
pull/1503/head
Benedikt Schroeder 9 years ago
parent
commit
77bd8c89ca
  1. 18
      src/Avalonia.Controls/Presenters/ContentPresenter.cs
  2. 268
      src/Avalonia.Controls/Utils/BorderRenderHelper.cs

18
src/Avalonia.Controls/Presenters/ContentPresenter.cs

@ -341,8 +341,8 @@ namespace Avalonia.Controls.Presenters
var horizontalContentAlignment = HorizontalContentAlignment;
var verticalContentAlignment = VerticalContentAlignment;
var useLayoutRounding = UseLayoutRounding;
var availableSizeMinusMargins = finalSize;
var sizeForChild = availableSizeMinusMargins;
var availableSize = finalSize;
var sizeForChild = availableSize;
var scale = GetLayoutScale();
var originX = offset.X;
var originY = offset.Y;
@ -362,28 +362,28 @@ namespace Avalonia.Controls.Presenters
sizeForChild = new Size(
Math.Ceiling(sizeForChild.Width * scale) / scale,
Math.Ceiling(sizeForChild.Height * scale) / scale);
availableSizeMinusMargins = new Size(
Math.Ceiling(availableSizeMinusMargins.Width * scale) / scale,
Math.Ceiling(availableSizeMinusMargins.Height * scale) / scale);
availableSize = new Size(
Math.Ceiling(availableSize.Width * scale) / scale,
Math.Ceiling(availableSize.Height * scale) / scale);
}
switch (horizontalContentAlignment)
{
case HorizontalAlignment.Center:
originX += (availableSizeMinusMargins.Width - sizeForChild.Width) / 2;
originX += (availableSize.Width - sizeForChild.Width) / 2;
break;
case HorizontalAlignment.Right:
originX += availableSizeMinusMargins.Width - sizeForChild.Width;
originX += availableSize.Width - sizeForChild.Width;
break;
}
switch (verticalContentAlignment)
{
case VerticalAlignment.Center:
originY += (availableSizeMinusMargins.Height - sizeForChild.Height) / 2;
originY += (availableSize.Height - sizeForChild.Height) / 2;
break;
case VerticalAlignment.Bottom:
originY += availableSizeMinusMargins.Height - sizeForChild.Height;
originY += availableSize.Height - sizeForChild.Height;
break;
}

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

@ -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; }
}
}
}

Loading…
Cancel
Save