diff --git a/src/Avalonia.Controls/Border.cs b/src/Avalonia.Controls/Border.cs
index 8acb3603c9..0382c8d675 100644
--- a/src/Avalonia.Controls/Border.cs
+++ b/src/Avalonia.Controls/Border.cs
@@ -3,6 +3,7 @@
using Avalonia;
using Avalonia.Controls.Utils;
+using Avalonia.Layout;
using Avalonia.Media;
namespace Avalonia.Controls
@@ -99,7 +100,7 @@ namespace Avalonia.Controls
/// The desired size of the control.
protected override Size MeasureOverride(Size availableSize)
{
- return MeasureOverrideImpl(availableSize, Child, Padding, BorderThickness);
+ return LayoutHelper.MeasureChild(Child, availableSize, Padding, BorderThickness);
}
///
@@ -109,32 +110,9 @@ namespace Avalonia.Controls
/// The space taken.
protected override Size ArrangeOverride(Size finalSize)
{
- if (Child != null)
- {
- var padding = Padding + BorderThickness;
- Child.Arrange(new Rect(finalSize).Deflate(padding));
- }
-
_borderRenderHelper.Update(finalSize, BorderThickness, CornerRadius);
- return finalSize;
- }
-
- internal static Size MeasureOverrideImpl(
- Size availableSize,
- IControl child,
- Thickness padding,
- Thickness borderThickness)
- {
- padding += borderThickness;
-
- if (child != null)
- {
- child.Measure(availableSize.Deflate(padding));
- return child.DesiredSize.Inflate(padding);
- }
-
- return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
+ return LayoutHelper.ArrangeChild(Child, finalSize, Padding, BorderThickness);
}
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Decorator.cs b/src/Avalonia.Controls/Decorator.cs
index 4040e4b8b7..389cf66d34 100644
--- a/src/Avalonia.Controls/Decorator.cs
+++ b/src/Avalonia.Controls/Decorator.cs
@@ -1,6 +1,7 @@
// 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.
+using Avalonia.Layout;
using Avalonia.Metadata;
namespace Avalonia.Controls
@@ -53,25 +54,13 @@ namespace Avalonia.Controls
///
protected override Size MeasureOverride(Size availableSize)
{
- var content = Child;
- var padding = Padding;
-
- if (content != null)
- {
- content.Measure(availableSize.Deflate(padding));
- return content.DesiredSize.Inflate(padding);
- }
- else
- {
- return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
- }
+ return LayoutHelper.MeasureChild(Child, availableSize, Padding);
}
///
protected override Size ArrangeOverride(Size finalSize)
{
- Child?.Arrange(new Rect(finalSize).Deflate(Padding));
- return finalSize;
+ return LayoutHelper.ArrangeChild(Child, finalSize, Padding);
}
///
diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
index 3cc750e20d..97c85b0c6c 100644
--- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
@@ -35,6 +35,13 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty BorderThicknessProperty =
Border.BorderThicknessProperty.AddOwner();
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty CornerRadiusProperty =
+ Border.CornerRadiusProperty.AddOwner();
+
+
///
/// Defines the property.
///
@@ -55,12 +62,6 @@ namespace Avalonia.Controls.Presenters
public static readonly StyledProperty ContentTemplateProperty =
ContentControl.ContentTemplateProperty.AddOwner();
- ///
- /// Defines the property.
- ///
- public static readonly StyledProperty CornerRadiusProperty =
- Border.CornerRadiusProperty.AddOwner();
-
///
/// Defines the property.
///
@@ -96,13 +97,6 @@ namespace Avalonia.Controls.Presenters
TemplatedParentProperty.Changed.AddClassHandler(x => x.TemplatedParentChanged);
}
- ///
- /// Initializes a new instance of the class.
- ///
- public ContentPresenter()
- {
- }
-
///
/// Gets or sets a brush with which to paint the background.
///
@@ -130,6 +124,15 @@ namespace Avalonia.Controls.Presenters
set { SetValue(BorderThicknessProperty, value); }
}
+ ///
+ /// Gets or sets the radius of the border rounded corners.
+ ///
+ public CornerRadius CornerRadius
+ {
+ get { return GetValue(CornerRadiusProperty); }
+ set { SetValue(CornerRadiusProperty, value); }
+ }
+
///
/// Gets the control displayed by the presenter.
///
@@ -159,16 +162,7 @@ namespace Avalonia.Controls.Presenters
}
///
- /// Gets or sets the radius of the border rounded corners.
- ///
- public CornerRadius CornerRadius
- {
- get { return GetValue(CornerRadiusProperty); }
- set { SetValue(CornerRadiusProperty, value); }
- }
-
- ///
- /// Gets or sets the horizontal alignment of the content within the control.
+ /// Gets or sets the horizontal alignment of the content within the border the control.
///
public HorizontalAlignment HorizontalContentAlignment
{
@@ -177,7 +171,7 @@ namespace Avalonia.Controls.Presenters
}
///
- /// Gets or sets the vertical alignment of the content within the control.
+ /// Gets or sets the vertical alignment of the content within the border of the control.
///
public VerticalAlignment VerticalContentAlignment
{
@@ -186,7 +180,7 @@ namespace Avalonia.Controls.Presenters
}
///
- /// Gets or sets the padding to place around the control.
+ /// Gets or sets the space between the border and the control.
///
public Thickness Padding
{
@@ -195,7 +189,7 @@ namespace Avalonia.Controls.Presenters
}
///
- public override sealed void ApplyTemplate()
+ public sealed override void ApplyTemplate()
{
if (!_createdChild && ((ILogical)this).IsAttachedToLogicalTree)
{
@@ -328,67 +322,41 @@ namespace Avalonia.Controls.Presenters
///
protected override Size MeasureOverride(Size availableSize)
{
- return Border.MeasureOverrideImpl(availableSize, Child, Padding, BorderThickness);
+ return LayoutHelper.MeasureChild(Child, availableSize, Padding, BorderThickness);
}
///
protected override Size ArrangeOverride(Size finalSize)
{
- finalSize = ArrangeOverrideImpl(finalSize, new Vector());
-
_borderRenderer.Update(finalSize, BorderThickness, CornerRadius);
- return finalSize;
- }
-
- ///
- /// Called when the property changes.
- ///
- /// The event args.
- private void ContentChanged(AvaloniaPropertyChangedEventArgs e)
- {
- _createdChild = false;
-
- if (((ILogical)this).IsAttachedToLogicalTree)
- {
- UpdateChild();
- }
- else if (Child != null)
- {
- VisualChildren.Remove(Child);
- LogicalChildren.Remove(Child);
- Child = null;
- _dataTemplate = null;
- }
-
- InvalidateMeasure();
+ return ArrangeOverrideImpl(finalSize, new Vector());
}
internal Size ArrangeOverrideImpl(Size finalSize, Vector offset)
{
if (Child == null) return finalSize;
- var padding = Padding;
- var borderThickness = BorderThickness;
+ var padding = Padding + BorderThickness;
var horizontalContentAlignment = HorizontalContentAlignment;
var verticalContentAlignment = VerticalContentAlignment;
var useLayoutRounding = UseLayoutRounding;
var availableSizeMinusMargins = new Size(
- Math.Max(0, finalSize.Width - padding.Left - padding.Right - borderThickness.Left - borderThickness.Right),
- Math.Max(0, finalSize.Height - padding.Top - padding.Bottom - borderThickness.Top - borderThickness.Bottom));
+ Math.Max(0, finalSize.Width),
+ Math.Max(0, finalSize.Height));
var size = availableSizeMinusMargins;
var scale = GetLayoutScale();
- var originX = offset.X + padding.Left + borderThickness.Left;
- var originY = offset.Y + padding.Top + borderThickness.Top;
+ var originX = offset.X;
+ var originY = offset.Y;
if (horizontalContentAlignment != HorizontalAlignment.Stretch)
{
- size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width - padding.Left - padding.Right));
+ size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width));
}
if (verticalContentAlignment != VerticalAlignment.Stretch)
{
- size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height - padding.Top - padding.Bottom));
+ size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height));
}
if (useLayoutRounding)
@@ -427,11 +395,37 @@ namespace Avalonia.Controls.Presenters
originY = Math.Floor(originY * scale) / scale;
}
- Child.Arrange(new Rect(originX, originY, Math.Max(0, size.Width), Math.Max(0, size.Height)));
+ var boundsForChild =
+ new Rect(originX, originY, Math.Max(0, size.Width), Math.Max(0, size.Height)).Deflate(padding);
+
+ Child.Arrange(boundsForChild);
return finalSize;
}
+ ///
+ /// Called when the property changes.
+ ///
+ /// The event args.
+ private void ContentChanged(AvaloniaPropertyChangedEventArgs e)
+ {
+ _createdChild = false;
+
+ if (((ILogical)this).IsAttachedToLogicalTree)
+ {
+ UpdateChild();
+ }
+ else if (Child != null)
+ {
+ VisualChildren.Remove(Child);
+ LogicalChildren.Remove(Child);
+ Child = null;
+ _dataTemplate = null;
+ }
+
+ InvalidateMeasure();
+ }
+
private double GetLayoutScale()
{
var result = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1.0;
diff --git a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
index d9169e51f3..e5b1b1961f 100644
--- a/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
+++ b/src/Avalonia.Controls/Utils/BorderRenderHelper.cs
@@ -26,7 +26,7 @@ namespace Avalonia.Controls.Utils
var boundRect = new Rect(finalSize);
var innerRect = boundRect.Deflate(borderThickness);
- var innerCoordinates = new BorderCoordinates(cornerRadius, borderThickness, false);
+ var innerCoordinates = GeometryCoordinates.CreateBackgroundCoordinates(cornerRadius, borderThickness);
StreamGeometry backgroundGeometry = null;
@@ -48,7 +48,7 @@ namespace Avalonia.Controls.Utils
if (boundRect.Width != 0 && innerRect.Height != 0)
{
- var outerCoordinates = new BorderCoordinates(cornerRadius, borderThickness, true);
+ var outerCoordinates = GeometryCoordinates.CreateBorderCoordinates(cornerRadius, borderThickness);
var borderGeometry = new StreamGeometry();
using (var ctx = borderGeometry.Open())
@@ -104,42 +104,41 @@ namespace Avalonia.Controls.Utils
}
}
- private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderCoordinates borderCoordinates)
+ private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, GeometryCoordinates geometryCoordinates)
{
- var topLeft = new Point(borderCoordinates.LeftTop, 0);
- var topRight = new Point(boundRect.Width - borderCoordinates.RightTop, 0);
- var rightTop = new Point(boundRect.Width, borderCoordinates.TopRight);
- var rightBottom = new Point(boundRect.Width, boundRect.Height - borderCoordinates.BottomRight);
- var bottomRight = new Point(boundRect.Width - borderCoordinates.RightBottom, boundRect.Height);
- var bottomLeft = new Point(borderCoordinates.LeftBottom, boundRect.Height);
- var leftBottom = new Point(0, boundRect.Height - borderCoordinates.BottomLeft);
- var leftTop = new Point(0, borderCoordinates.TopLeft);
-
+ 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)
{
- var scaledX = borderCoordinates.LeftTop / (borderCoordinates.LeftTop + borderCoordinates.RightTop) * boundRect.Width;
+ var scaledX = geometryCoordinates.LeftTop / (geometryCoordinates.LeftTop + geometryCoordinates.RightTop) * boundRect.Width;
topLeft = new Point(scaledX, topLeft.Y);
topRight = new Point(scaledX, topRight.Y);
}
if (rightTop.Y > rightBottom.Y)
{
- var scaledY = borderCoordinates.TopRight / (borderCoordinates.TopRight + borderCoordinates.BottomRight) * boundRect.Height;
+ var scaledY = geometryCoordinates.TopRight / (geometryCoordinates.TopRight + geometryCoordinates.BottomRight) * boundRect.Height;
rightTop = new Point(rightTop.X, scaledY);
rightBottom = new Point(rightBottom.X, scaledY);
}
if (bottomRight.X < bottomLeft.X)
{
- var scaledX = borderCoordinates.LeftBottom / (borderCoordinates.LeftBottom + borderCoordinates.RightBottom) * boundRect.Width;
+ var scaledX = geometryCoordinates.LeftBottom / (geometryCoordinates.LeftBottom + geometryCoordinates.RightBottom) * boundRect.Width;
bottomRight = new Point(scaledX, bottomRight.Y);
bottomLeft = new Point(scaledX, bottomLeft.Y);
}
if (leftBottom.Y < leftTop.Y)
{
- var scaledY = borderCoordinates.TopLeft / (borderCoordinates.TopLeft + borderCoordinates.BottomLeft) * boundRect.Height;
+ var scaledY = geometryCoordinates.TopLeft / (geometryCoordinates.TopLeft + geometryCoordinates.BottomLeft) * boundRect.Height;
leftBottom = new Point(leftBottom.X, scaledY);
leftTop = new Point(leftTop.X, scaledY);
}
@@ -204,75 +203,88 @@ namespace Avalonia.Controls.Utils
context.EndFigure(true);
}
- private struct BorderCoordinates
+ private struct GeometryCoordinates
{
- internal BorderCoordinates(CornerRadius cornerRadius, Thickness borderThickness, bool isOuter)
+ 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;
- if (isOuter)
+ var leftTop = 0.0;
+ var topLeft = 0.0;
+ if (cornerRadius.TopLeft != 0)
{
- if (cornerRadius.TopLeft == 0)
- {
- LeftTop = TopLeft = 0.0;
- }
- else
- {
- LeftTop = cornerRadius.TopLeft + left;
- TopLeft = cornerRadius.TopLeft + top;
- }
- if (cornerRadius.TopRight == 0)
- {
- TopRight = RightTop = 0;
- }
- else
- {
- TopRight = cornerRadius.TopRight + top;
- RightTop = cornerRadius.TopRight + right;
- }
- if (cornerRadius.BottomRight == 0)
- {
- RightBottom = BottomRight = 0;
- }
- else
- {
- RightBottom = cornerRadius.BottomRight + right;
- BottomRight = cornerRadius.BottomRight + bottom;
- }
- if (cornerRadius.BottomLeft == 0)
- {
- BottomLeft = LeftBottom = 0;
- }
- else
- {
- BottomLeft = cornerRadius.BottomLeft + bottom;
- LeftBottom = cornerRadius.BottomLeft + left;
- }
+ leftTop = cornerRadius.TopLeft + left;
+ topLeft = cornerRadius.TopLeft + top;
}
- else
+
+ var topRight = 0.0;
+ var rightTop = 0.0;
+ if (cornerRadius.TopRight != 0)
{
- 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);
+ 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 readonly double LeftTop;
- internal readonly double TopLeft;
- internal readonly double TopRight;
- internal readonly double RightTop;
- internal readonly double RightBottom;
- internal readonly double BottomRight;
- internal readonly double BottomLeft;
- internal readonly double LeftBottom;
+ 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; }
}
}
diff --git a/src/Avalonia.Layout/LayoutHelper.cs b/src/Avalonia.Layout/LayoutHelper.cs
index 8c0a6a579b..d77cc269f9 100644
--- a/src/Avalonia.Layout/LayoutHelper.cs
+++ b/src/Avalonia.Layout/LayoutHelper.cs
@@ -29,5 +29,34 @@ namespace Avalonia.Layout
height = Math.Max(height, control.MinHeight);
return new Size(width, height);
}
+
+ public static Size MeasureChild(ILayoutable control, Size availableSize, Thickness padding,
+ Thickness borderThickness)
+ {
+ return MeasureChild(control, availableSize, padding + borderThickness);
+ }
+
+ public static Size MeasureChild(ILayoutable control, Size availableSize, Thickness padding)
+ {
+ if (control != null)
+ {
+ control.Measure(availableSize.Deflate(padding));
+ return control.DesiredSize.Inflate(padding);
+ }
+
+ return new Size(padding.Left + padding.Right, padding.Bottom + padding.Top);
+ }
+
+ public static Size ArrangeChild(ILayoutable child, Size availableSize, Thickness padding, Thickness borderThickness)
+ {
+ return ArrangeChild(child, availableSize, padding + borderThickness);
+ }
+
+ public static Size ArrangeChild(ILayoutable child, Size availableSize, Thickness padding)
+ {
+ child?.Arrange(new Rect(availableSize).Deflate(padding));
+
+ return availableSize;
+ }
}
}