Skip to content

Commit

Permalink
Restore Rectangle parameter for ArrangeChildren (#2014)
Browse files Browse the repository at this point in the history
  • Loading branch information
hartez committed Aug 10, 2021
1 parent d878703 commit eab6a1e
Show file tree
Hide file tree
Showing 17 changed files with 110 additions and 68 deletions.
6 changes: 3 additions & 3 deletions src/Controls/src/Core/Layout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ Size ILayoutManager.Measure(double widthConstraint, double heightConstraint)
return OnMeasure(widthConstraint, heightConstraint);
}

Size ILayoutManager.ArrangeChildren(Size finalSize)
Size ILayoutManager.ArrangeChildren(Rectangle bounds)
{
LayoutChildren(0, 0, finalSize.Width, finalSize.Height);
return finalSize;
LayoutChildren(bounds.X, bounds.Y, bounds.Width, bounds.Height);
return bounds.Size;
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/Core/src/Layouts/FlexLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public FlexLayoutManager(IFlexLayout flexLayout)
FlexLayout = flexLayout;
}

public Size ArrangeChildren(Size finalSize)
public Size ArrangeChildren(Rectangle bounds)
{
FlexLayout.Layout(finalSize.Width, finalSize.Height);
FlexLayout.Layout(bounds.Width, bounds.Height);

foreach (var child in FlexLayout)
{
Expand All @@ -25,11 +25,11 @@ public Size ArrangeChildren(Size finalSize)
|| double.IsNaN(frame.Width)
|| double.IsNaN(frame.Height))
throw new Exception("something is deeply wrong");

frame = frame.Offset(bounds.Left, bounds.Top);
child.Arrange(frame);
}

return finalSize;
return bounds.Size;
}

public Size Measure(double widthConstraint, double heightConstraint)
Expand Down
10 changes: 5 additions & 5 deletions src/Core/src/Layouts/GridLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ public override Size Measure(double widthConstraint, double heightConstraint)
return new Size(_gridStructure.MeasuredGridWidth(), _gridStructure.MeasuredGridHeight());
}

public override Size ArrangeChildren(Size finalSize)
public override Size ArrangeChildren(Rectangle bounds)
{
var structure = _gridStructure ?? new GridStructure(Grid, finalSize.Width, finalSize.Height);
var structure = _gridStructure ?? new GridStructure(Grid, bounds.Width, bounds.Height);

foreach (var view in Grid)
{
Expand All @@ -33,7 +33,7 @@ public override Size ArrangeChildren(Size finalSize)
continue;
}

var cell = structure.GetCellBoundsFor(view);
var cell = structure.GetCellBoundsFor(view, bounds.Left, bounds.Top);

view.Arrange(cell);
}
Expand Down Expand Up @@ -187,7 +187,7 @@ void InitializeCells()
}
}

public Rectangle GetCellBoundsFor(IView view)
public Rectangle GetCellBoundsFor(IView view, double xOffset, double yOffset)
{
var firstColumn = _grid.GetColumn(view).Clamp(0, _columns.Length - 1);
var lastColumn = firstColumn + _grid.GetColumnSpan(view).Clamp(1, _columns.Length - firstColumn);
Expand Down Expand Up @@ -215,7 +215,7 @@ public Rectangle GetCellBoundsFor(IView view)
// TODO ezhart this isn't correctly accounting for row spacing when spanning multiple rows
// (and column spacing is probably wrong, too)

return new Rectangle(left, top, width, height);
return new Rectangle(left + xOffset, top + yOffset, width, height);
}

public double GridHeight()
Expand Down
12 changes: 7 additions & 5 deletions src/Core/src/Layouts/HorizontalStackLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,23 @@ public override Size Measure(double widthConstraint, double heightConstraint)
return new Size(finalWidth, finalHeight);
}

public override Size ArrangeChildren(Size finalSize)
public override Size ArrangeChildren(Rectangle bounds)
{
var padding = Stack.Padding;
var height = finalSize.Height - padding.VerticalThickness;
double stackWidth = 0;
double top = padding.Top + bounds.Top;
double left = padding.Left + bounds.Left;
var height = bounds.Height - padding.VerticalThickness;
double stackWidth;

if (Stack.FlowDirection == FlowDirection.LeftToRight)
{
stackWidth = ArrangeLeftToRight(height, padding.Left, padding.Top, Stack.Spacing, Stack);
stackWidth = ArrangeLeftToRight(height, left, top, Stack.Spacing, Stack);
}
else
{
// We _could_ simply reverse the list of child views when arranging from right to left,
// but this way we avoid extra list and enumerator allocations
stackWidth = ArrangeRightToLeft(height, padding.Left, padding.Top, Stack.Spacing, Stack);
stackWidth = ArrangeRightToLeft(height, left, top, Stack.Spacing, Stack);
}

return new Size(height, stackWidth);
Expand Down
3 changes: 1 addition & 2 deletions src/Core/src/Layouts/ILayoutManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Microsoft.Maui;
using Microsoft.Maui.Graphics;

namespace Microsoft.Maui.Layouts
Expand All @@ -7,6 +6,6 @@ public interface ILayoutManager
{
Size Measure(double widthConstraint, double heightConstraint);

Size ArrangeChildren(Size finalSize);
Size ArrangeChildren(Rectangle bounds);
}
}
2 changes: 1 addition & 1 deletion src/Core/src/Layouts/LayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public LayoutManager(ILayout layout)
public ILayout Layout { get; }

public abstract Size Measure(double widthConstraint, double heightConstraint);
public abstract Size ArrangeChildren(Size finalSize);
public abstract Size ArrangeChildren(Rectangle bounds);

public static double ResolveConstraints(double externalConstraint, double explicitLength, double measuredLength)
{
Expand Down
9 changes: 4 additions & 5 deletions src/Core/src/Layouts/VerticalStackLayoutManager.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Microsoft.Maui.Graphics;

namespace Microsoft.Maui.Layouts
Expand Down Expand Up @@ -41,13 +40,13 @@ public override Size Measure(double widthConstraint, double heightConstraint)
return new Size(finalWidth, finalHeight);
}

public override Size ArrangeChildren(Size finalSize)
public override Size ArrangeChildren(Rectangle bounds)
{
var padding = Stack.Padding;

double stackHeight = padding.Top;
double left = padding.Left;
double width = finalSize.Width - padding.HorizontalThickness;
double stackHeight = padding.Top + bounds.Y;
double left = padding.Left + bounds.X;
double width = bounds.Width - padding.HorizontalThickness;

for (int n = 0; n < Stack.Count; n++)
{
Expand Down
7 changes: 4 additions & 3 deletions src/Core/src/Platform/Android/LayoutViewGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ protected override void OnLayout(bool changed, int l, int t, int r, int b)
var deviceIndependentRight = Context.FromPixels(r);
var deviceIndependentBottom = Context.FromPixels(b);

var finalSize = new Size(deviceIndependentRight - deviceIndependentLeft, deviceIndependentBottom - deviceIndependentTop);
var destination = Rectangle.FromLTRB(0, 0,
deviceIndependentRight - deviceIndependentLeft, deviceIndependentBottom - deviceIndependentTop);

CrossPlatformArrange(finalSize);
CrossPlatformArrange(destination);
}

internal Func<double, double, Size>? CrossPlatformMeasure { get; set; }
internal Func<Size, Size>? CrossPlatformArrange { get; set; }
internal Func<Rectangle, Size>? CrossPlatformArrange { get; set; }
}
}
4 changes: 2 additions & 2 deletions src/Core/src/Platform/Windows/LayoutPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Microsoft.Maui
public class LayoutPanel : Panel
{
internal Func<double, double, Size>? CrossPlatformMeasure { get; set; }
internal Func<Size, Size>? CrossPlatformArrange { get; set; }
internal Func<Rectangle, Size>? CrossPlatformArrange { get; set; }

protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize)
{
Expand Down Expand Up @@ -38,7 +38,7 @@ protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Si
var width = finalSize.Width;
var height = finalSize.Height;

var actual = CrossPlatformArrange(new Size(width, height));
var actual = CrossPlatformArrange(new Rectangle(0, 0, width, height));

return new Windows.Foundation.Size(actual.Width, actual.Height);
}
Expand Down
11 changes: 5 additions & 6 deletions src/Core/src/Platform/iOS/LayoutView.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using CoreGraphics;
using Microsoft.Maui.Graphics;
using UIKit;
using ObjCRuntime;

namespace Microsoft.Maui
{
Expand All @@ -25,16 +27,13 @@ public override void LayoutSubviews()
{
base.LayoutSubviews();

// TODO ezhart 2021-07-07 This Frame may not make sense if we're applying a transform to this UIView; we should determine the rectangle from Bounds/Center instead
Frame = AdjustForSafeArea(Frame);

var bounds = Frame.ToRectangle();
var bounds = AdjustForSafeArea(Bounds).ToRectangle();

CrossPlatformMeasure?.Invoke(bounds.Width, bounds.Height);
CrossPlatformArrange?.Invoke(bounds.Size);
CrossPlatformArrange?.Invoke(bounds);
}

internal Func<double, double, Size>? CrossPlatformMeasure { get; set; }
internal Func<Size, Size>? CrossPlatformArrange { get; set; }
internal Func<Rectangle, Size>? CrossPlatformArrange { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public override bool FinishedLaunching(UIApplication application, NSDictionary l
UIWindow CreateNativeWindow()
{
var uiWindow = new UIWindow();

var mauiContext = new MauiContext(Services, uiWindow);

Services.InvokeLifecycleEvents<iOSLifecycle.OnMauiContextCreated>(del => del(mauiContext));
Expand Down
6 changes: 3 additions & 3 deletions src/Core/src/Platform/iOS/MauiView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ bool RespondsToSafeArea()
return (bool)(_respondsToSafeArea = RespondsToSelector(new Selector("safeAreaInsets")));
}

protected CGRect AdjustForSafeArea(CGRect frame)
protected CGRect AdjustForSafeArea(CGRect bounds)
{
if (View is not ISafeAreaView sav || sav.IgnoreSafeArea || !RespondsToSafeArea())
{
return frame;
return bounds;
}

return SafeAreaInsets.InsetRect(frame);
return SafeAreaInsets.InsetRect(bounds);
}
}
}
4 changes: 1 addition & 3 deletions src/Core/src/Platform/iOS/PageView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ public override void LayoutSubviews()
{
base.LayoutSubviews();

Frame = AdjustForSafeArea(Frame);

var bounds = Frame.ToRectangle();
var bounds = AdjustForSafeArea(Bounds).ToRectangle();

CrossPlatformMeasure?.Invoke(bounds.Width, bounds.Height);
CrossPlatformArrange?.Invoke(bounds);
Expand Down
4 changes: 2 additions & 2 deletions src/Core/tests/DeviceTests/Stubs/LayoutManagerStub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ namespace Microsoft.Maui.DeviceTests.Stubs
{
public class LayoutManagerStub : ILayoutManager
{
public Size ArrangeChildren(Size finalSize)
public Size ArrangeChildren(Rectangle bounds)
{
return finalSize;
return bounds.Size;
}

public Size Measure(double widthConstraint, double heightConstraint)
Expand Down
36 changes: 26 additions & 10 deletions src/Core/tests/UnitTests/Layouts/GridLayoutManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ void SetLocation(IGridLayout grid, IView view, int row = 0, int col = 0, int row
grid.GetColumnSpan(view).Returns(colSpan);
}

Size MeasureAndArrange(IGridLayout grid, double widthConstraint = double.PositiveInfinity, double heightConstraint = double.PositiveInfinity)
Size MeasureAndArrange(IGridLayout grid, double widthConstraint = double.PositiveInfinity, double heightConstraint = double.PositiveInfinity, double left = 0, double top = 0)
{
var manager = new GridLayoutManager(grid);
var measuredSize = manager.Measure(widthConstraint, heightConstraint);
manager.ArrangeChildren(measuredSize);
manager.ArrangeChildren(new Rectangle(new Point(left, top), measuredSize));

return measuredSize;
}
Expand Down Expand Up @@ -336,7 +336,7 @@ public void EmptyAutoRowsHaveNoHeight()

var manager = new GridLayoutManager(grid);
var measure = manager.Measure(double.PositiveInfinity, double.PositiveInfinity);
manager.ArrangeChildren(new Size(measure.Width, measure.Height));
manager.ArrangeChildren(new Rectangle(0, 0, measure.Width, measure.Height));

// Because the auto row has no content, we expect it to have height zero
Assert.Equal(100 + 100, measure.Height);
Expand Down Expand Up @@ -424,7 +424,7 @@ public void EmptyAutoColumnsHaveNoWidth()

var manager = new GridLayoutManager(grid);
var measure = manager.Measure(double.PositiveInfinity, double.PositiveInfinity);
manager.ArrangeChildren(new Size(measure.Width, measure.Height));
manager.ArrangeChildren(new Rectangle(0, 0, measure.Width, measure.Height));

// Because the auto column has no content, we expect it to have width zero
Assert.Equal(100 + 100, measure.Width);
Expand Down Expand Up @@ -703,7 +703,7 @@ public void CanSpanAbsoluteColumns()
var manager = new GridLayoutManager(grid);

manager.Measure(200, 100);
manager.ArrangeChildren(new Size(200, 100));
manager.ArrangeChildren(new Rectangle(0, 0, 200, 100));

// View should be arranged to span both columns (200 points)
AssertArranged(view0, 0, 0, 200, 100);
Expand All @@ -721,7 +721,7 @@ public void CanSpanAbsoluteRows()
var manager = new GridLayoutManager(grid);

manager.Measure(100, 200);
manager.ArrangeChildren(new Size(100, 200));
manager.ArrangeChildren(new Rectangle(0, 0, 100, 200));

// View should be arranged to span both rows (200 points)
AssertArranged(view0, 0, 0, 100, 200);
Expand Down Expand Up @@ -1095,7 +1095,7 @@ public void IgnoresCollapsedViews()

var manager = new GridLayoutManager(grid);
var measure = manager.Measure(100, double.PositiveInfinity);
manager.ArrangeChildren(measure);
manager.ArrangeChildren(new Rectangle(Point.Zero, measure));

// View is visible, so we expect it to be measured and arranged
view.Received().Measure(Arg.Any<double>(), Arg.Any<double>());
Expand All @@ -1117,7 +1117,7 @@ public void DoesNotIgnoreHiddenViews()

var manager = new GridLayoutManager(grid);
var measure = manager.Measure(100, double.PositiveInfinity);
manager.ArrangeChildren(measure);
manager.ArrangeChildren(new Rectangle(Point.Zero, measure));

// View is visible, so we expect it to be measured and arranged
view.Received().Measure(Arg.Any<double>(), Arg.Any<double>());
Expand Down Expand Up @@ -1180,7 +1180,7 @@ public void ArrangeAccountsForPadding(double left, double top, double right, dou

var manager = new GridLayoutManager(grid);
var measuredSize = manager.Measure(double.PositiveInfinity, double.PositiveInfinity);
manager.ArrangeChildren(measuredSize);
manager.ArrangeChildren(new Rectangle(Point.Zero, measuredSize));

AssertArranged(grid[0], padding.Left, padding.Top, viewWidth, viewHeight);
}
Expand Down Expand Up @@ -1211,7 +1211,7 @@ public void StarValuesAreMeasuredTwiceWhenConstraintsAreInfinite()
}

[Fact]
public void GridMeasureShouldUseExplicitHeight()
public void GridMeasureShouldUseExplicitHeight()
{
var grid = CreateGridLayout();
var view = CreateTestView(new Size(10, 10));
Expand Down Expand Up @@ -1327,5 +1327,21 @@ public void SpansOutsideRowsAndColsClampsToGrid(int row, int col, int rowSpan, i
100 * actualColSpan,
100 * actualRowSpan);
}

[Fact]
public void ArrangeRespectsBounds()
{
var grid = CreateGridLayout();
var view = CreateTestView(new Size(100, 100));

SubstituteChildren(grid, view);
SetLocation(grid, view);

var measure = MeasureAndArrange(grid, double.PositiveInfinity, double.PositiveInfinity, 10, 15);

var expectedRectangle = new Rectangle(10, 15, measure.Width, measure.Height);

view.Received().Arrange(Arg.Is(expectedRectangle));
}
}
}
Loading

0 comments on commit eab6a1e

Please sign in to comment.