Skip to content

Commit

Permalink
Limit star expansion when measuring/arranging at constrained sizes (#…
Browse files Browse the repository at this point in the history
…17880)

### Description of Change

For constrained measurement, when definition sizes are determined during
the measure pass the star sizes are limited by the number of stars which
can fit into the constraint. During arrange, if the actual arrange size
is different, then the size of a star definition needs to be limited by
the number of stars which can fit into the arranged size.

Proposing this as an alternative to #17199 - this is a less extensive
change to achieve the same effect.

### Issues Fixed

Fixes #17125
  • Loading branch information
rmarinho authored Oct 16, 2023
2 parents b8f7e4f + 42788ad commit 0f764ac
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 5 deletions.
42 changes: 37 additions & 5 deletions src/Core/src/Layouts/GridLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -813,12 +813,20 @@ public void PrepareForArrange(Size targetSize)

if (expandStarRows)
{
ExpandStarDefinitions(_rows, targetSize.Height - _padding.VerticalThickness, GridMinimumHeight() - _padding.VerticalThickness, _rowSpacing, _rowStarCount);
// If the grid is constrained vertically, we will need to limit the upper size of * rows;
// if not, they can be whatever size makes sense for the content
var limitStarRowHeights = !double.IsInfinity(_gridHeightConstraint);
ExpandStarDefinitions(_rows, targetSize.Height - _padding.VerticalThickness, GridMinimumHeight() - _padding.VerticalThickness,
_rowSpacing, _rowStarCount, limitStarRowHeights);
}

if (expandStarColumns)
{
ExpandStarDefinitions(_columns, targetSize.Width - _padding.HorizontalThickness, GridMinimumWidth() - _padding.HorizontalThickness, _columnSpacing, _columnStarCount);
// If the grid is constrained horizontally, we will need to limit the upper size of * columns;
// if not, they can be whatever size makes sense for the content
var limitStarRowWidths = !double.IsInfinity(_gridWidthConstraint);
ExpandStarDefinitions(_columns, targetSize.Width - _padding.HorizontalThickness, GridMinimumWidth() - _padding.HorizontalThickness,
_columnSpacing, _columnStarCount, limitStarRowWidths);
}
}

Expand All @@ -833,16 +841,40 @@ static void MinimizeStars(Definition[] defs)
}
}

void ExpandStarDefinitions(Definition[] definitions, double targetSize, double currentSize, double spacing, double starCount)
static void ExpandStarDefinitions(Definition[] definitions, double targetSize, double currentSize, double spacing, double starCount, bool limitStarSizes)
{
// Figure out what the star value should be at this size
var starSize = ComputeStarSizeForTarget(targetSize, definitions, spacing, starCount);

if (limitStarSizes)
{
// Before we expand the star values, we need to ensure that the size and minimum size of
// each star row/column do not exceed the value for starSize at the arranged size
// (which may be smaller than the measured size)
EnsureSizeLimit(definitions, starSize);
}

// Inflate the stars so that we fill up the space at this size
GridStructure.ExpandStars(targetSize, currentSize, definitions, starSize, starCount);
ExpandStars(targetSize, currentSize, definitions, starSize, starCount);
}

static void EnsureSizeLimit(Definition[] definitions, double starSize)
{
for (int n = 0; n < definitions.Length; n++)
{
var def = definitions[n];
if (!def.IsStar)
{
continue;
}

var maxSize = starSize * def.GridLength.Value;
def.Size = Math.Min(maxSize, def.Size);
def.MinimumSize = Math.Min(maxSize, def.MinimumSize);
}
}

double ComputeStarSizeForTarget(double targetSize, Definition[] defs, double spacing, double starCount)
static double ComputeStarSizeForTarget(double targetSize, Definition[] defs, double spacing, double starCount)
{
var sum = SumDefinitions(defs, spacing, true);

Expand Down
62 changes: 62 additions & 0 deletions src/Core/tests/UnitTests/Layouts/GridLayoutManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3170,5 +3170,67 @@ public void AutoRowIntersectionWithUnconstrainedMeasure()
// Ensure that the * Column width was updated to include the wider view
AssertArranged(view0, new Rect(0, 0, 40, 20));
}

[Theory, Category(GridStarSizing)]
[InlineData(926, 845)]
[InlineData(926, 926)]
[InlineData(926, 1026)]
public void StarsAdjustWhenArrangeAndMeasureHeightDiffer(double heightConstraint, double arrangedHeight)
{
var grid = CreateGridLayout(rows: "*, *", columns: "*");

var smallerView = CreateTestView(new Size(20, 20));
var largerView = CreateTestView(new Size(20, 500));

SubstituteChildren(grid, largerView, smallerView);

SetLocation(grid, smallerView, col: 0, row: 0);
SetLocation(grid, largerView, row: 1, col: 0);

var gridLayoutManager = new GridLayoutManager(grid);

double widthConstraint = 400;

_ = gridLayoutManager.Measure(widthConstraint, heightConstraint);

// Arranging at a different size than the measurement constraints
gridLayoutManager.ArrangeChildren(new Rect(0, 0, widthConstraint, arrangedHeight));

double expectedHeight = arrangedHeight / 2;

AssertArranged(smallerView, new Rect(0, 0, widthConstraint, expectedHeight));
AssertArranged(largerView, new Rect(0, expectedHeight, widthConstraint, expectedHeight));
}

[Theory, Category(GridStarSizing)]
[InlineData(926, 845)]
[InlineData(926, 926)]
[InlineData(926, 1026)]
public void StarsAdjustWhenArrangeAndMeasureWidthDiffer(double widthConstraint, double arrangedWidth)
{
var grid = CreateGridLayout(rows: "*", columns: "*, *");

var smallerView = CreateTestView(new Size(20, 20));
var largerView = CreateTestView(new Size(500, 20));

SubstituteChildren(grid, largerView, smallerView);

SetLocation(grid, smallerView, col: 0, row: 0);
SetLocation(grid, largerView, row: 0, col: 1);

var gridLayoutManager = new GridLayoutManager(grid);

double heightConstraint = 400;

_ = gridLayoutManager.Measure(widthConstraint, heightConstraint);

// Arranging at a different size than the measurement constraints
gridLayoutManager.ArrangeChildren(new Rect(0, 0, arrangedWidth, heightConstraint));

double expectedWidth = arrangedWidth / 2;

AssertArranged(smallerView, new Rect(0, 0, expectedWidth, heightConstraint));
AssertArranged(largerView, new Rect(expectedWidth, 0, expectedWidth, heightConstraint));
}
}
}

0 comments on commit 0f764ac

Please sign in to comment.