diff --git a/src/Perspex.Layout/Layoutable.cs b/src/Perspex.Layout/Layoutable.cs index 4c72f39043..9caa836d30 100644 --- a/src/Perspex.Layout/Layoutable.cs +++ b/src/Perspex.Layout/Layoutable.cs @@ -521,24 +521,27 @@ namespace Perspex.Layout { if (IsVisible) { - var originX = finalRect.X + Margin.Left; - var originY = finalRect.Y + Margin.Top; - var sizeMinusMargins = new Size( - Math.Max(0, finalRect.Width - Margin.Left - Margin.Right), - Math.Max(0, finalRect.Height - Margin.Top - Margin.Bottom)); + var margin = Margin; + var originX = finalRect.X + margin.Left; + var originY = finalRect.Y + margin.Top; + var availableSizeMinusMargins = new Size( + Math.Max(0, finalRect.Width - margin.Left - margin.Right), + Math.Max(0, finalRect.Height - margin.Top - margin.Bottom)); var horizontalAlignment = HorizontalAlignment; var verticalAlignment = VerticalAlignment; - var size = sizeMinusMargins; + var size = availableSizeMinusMargins; var scale = GetLayoutScale(); if (horizontalAlignment != HorizontalAlignment.Stretch) { - size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width)); + size = size.WithWidth(Math.Min(size.Width, DesiredSize.Width) + - margin.Left - margin.Right); } if (verticalAlignment != VerticalAlignment.Stretch) { - size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height)); + size = size.WithHeight(Math.Min(size.Height, DesiredSize.Height) + - margin.Top - margin.Bottom); } size = LayoutHelper.ApplyLayoutConstraints(this, size); @@ -548,9 +551,9 @@ namespace Perspex.Layout size = new Size( Math.Ceiling(size.Width * scale) / scale, Math.Ceiling(size.Height * scale) / scale); - sizeMinusMargins = new Size( - Math.Ceiling(sizeMinusMargins.Width * scale) / scale, - Math.Ceiling(sizeMinusMargins.Height * scale) / scale); + availableSizeMinusMargins = new Size( + Math.Ceiling(availableSizeMinusMargins.Width * scale) / scale, + Math.Ceiling(availableSizeMinusMargins.Height * scale) / scale); } size = ArrangeOverride(size).Constrain(size); @@ -559,10 +562,10 @@ namespace Perspex.Layout { case HorizontalAlignment.Center: case HorizontalAlignment.Stretch: - originX += (sizeMinusMargins.Width - size.Width) / 2; + originX += (availableSizeMinusMargins.Width - size.Width) / 2; break; case HorizontalAlignment.Right: - originX += sizeMinusMargins.Width - size.Width; + originX += availableSizeMinusMargins.Width - size.Width; break; } @@ -570,10 +573,10 @@ namespace Perspex.Layout { case VerticalAlignment.Center: case VerticalAlignment.Stretch: - originY += (sizeMinusMargins.Height - size.Height) / 2; + originY += (availableSizeMinusMargins.Height - size.Height) / 2; break; case VerticalAlignment.Bottom: - originY += sizeMinusMargins.Height - size.Height; + originY += availableSizeMinusMargins.Height - size.Height; break; } diff --git a/tests/Perspex.Layout.UnitTests/ArrangeTests.cs b/tests/Perspex.Layout.UnitTests/ArrangeTests.cs index 88e52c1303..ceb69ec8ca 100644 --- a/tests/Perspex.Layout.UnitTests/ArrangeTests.cs +++ b/tests/Perspex.Layout.UnitTests/ArrangeTests.cs @@ -8,6 +8,56 @@ namespace Perspex.Layout.UnitTests { public class ArrangeTests { + [Fact] + public void Margin_Should_Be_Subtracted_From_Arrange_FinalSize() + { + var target = new TestControl + { + Width = 100, + Height = 100, + Margin = new Thickness(8), + }; + + target.Measure(Size.Infinity); + target.Arrange(new Rect(target.DesiredSize)); + + Assert.Equal(new Size(100, 100), target.ArrangeFinalSize); + } + + [Fact] + public void ArrangeOverride_Receives_Desired_Size_When_Centered() + { + var target = new TestControl + { + MeasureResult = new Size(100, 100), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Margin = new Thickness(8), + }; + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + target.Arrange(new Rect(0, 0, 200, 200)); + + Assert.Equal(new Size(100, 100), target.ArrangeFinalSize); + } + + [Fact] + public void ArrangeOverride_Receives_Available_Size_Minus_Margin_When_Stretched() + { + var target = new TestControl + { + MeasureResult = new Size(100, 100), + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Stretch, + Margin = new Thickness(8), + }; + + target.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); + target.Arrange(new Rect(0, 0, 200, 200)); + + Assert.Equal(new Size(184, 184), target.ArrangeFinalSize); + } + [Fact] public void Arrange_With_IsMeasureValid_False_Calls_Measure() { @@ -32,14 +82,24 @@ namespace Perspex.Layout.UnitTests Assert.Equal(new Size(120, 120), target.MeasureConstraint); } - private class TestControl : Border + private class TestControl : Decorator { public Size MeasureConstraint { get; private set; } + public Size MeasureResult { get; set; } + + public Size ArrangeFinalSize { get; private set; } + protected override Size MeasureOverride(Size constraint) { MeasureConstraint = constraint; - return base.MeasureOverride(constraint); + return MeasureResult; + } + + protected override Size ArrangeOverride(Size finalSize) + { + ArrangeFinalSize = finalSize; + return base.ArrangeOverride(finalSize); } } } diff --git a/tests/Perspex.Layout.UnitTests/MeasureTests.cs b/tests/Perspex.Layout.UnitTests/MeasureTests.cs index bbc69e90a2..7e0f4b7ce5 100644 --- a/tests/Perspex.Layout.UnitTests/MeasureTests.cs +++ b/tests/Perspex.Layout.UnitTests/MeasureTests.cs @@ -8,6 +8,21 @@ namespace Perspex.Layout.UnitTests { public class MeasureTests { + [Fact] + public void Margin_Should_Be_Included_In_DesiredSize() + { + var decorator = new Decorator + { + Width = 100, + Height = 100, + Margin = new Thickness(8), + }; + + decorator.Measure(Size.Infinity); + + Assert.Equal(new Size(116, 116), decorator.DesiredSize); + } + [Fact] public void Invalidating_Child_Should_Not_Invalidate_Parent() {