Skip to content

Commit f42af48

Browse files
authored
[Grid] Fix size calculation for ranges (#18621)
* Fix size calculation for range * Add unit tests * Clean code * More correct fix * Clean code (remove unused params) * Delete accidentally added file
1 parent 42f0790 commit f42af48

File tree

2 files changed

+137
-25
lines changed

2 files changed

+137
-25
lines changed

src/Avalonia.Controls/Grid.cs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ protected override Size MeasureOverride(Size constraint)
445445
// appears in Auto column.
446446
//
447447

448-
MeasureCellsGroup(extData.CellGroup1, constraint, false, false);
448+
MeasureCellsGroup(extData.CellGroup1, false, false);
449449
double rowSpacing = RowSpacing;
450450
double columnSpacing = ColumnSpacing;
451451
double combinedRowSpacing = RowSpacing * (RowDefinitions.Count - 1);
@@ -458,9 +458,9 @@ protected override Size MeasureOverride(Size constraint)
458458
if (canResolveStarsV)
459459
{
460460
if (HasStarCellsV) { ResolveStar(DefinitionsV, innerAvailableSize.Height); }
461-
MeasureCellsGroup(extData.CellGroup2, innerAvailableSize, false, false);
461+
MeasureCellsGroup(extData.CellGroup2, false, false);
462462
if (HasStarCellsU) { ResolveStar(DefinitionsU, innerAvailableSize.Width); }
463-
MeasureCellsGroup(extData.CellGroup3, innerAvailableSize, false, false);
463+
MeasureCellsGroup(extData.CellGroup3, false, false);
464464
}
465465
else
466466
{
@@ -470,7 +470,7 @@ protected override Size MeasureOverride(Size constraint)
470470
if (canResolveStarsU)
471471
{
472472
if (HasStarCellsU) { ResolveStar(DefinitionsU, innerAvailableSize.Width); }
473-
MeasureCellsGroup(extData.CellGroup3, innerAvailableSize, false, false);
473+
MeasureCellsGroup(extData.CellGroup3, false, false);
474474
if (HasStarCellsV) { ResolveStar(DefinitionsV, innerAvailableSize.Height); }
475475
}
476476
else
@@ -487,7 +487,7 @@ protected override Size MeasureOverride(Size constraint)
487487
double[] group2MinSizes = CacheMinSizes(extData.CellGroup2, false);
488488
double[] group3MinSizes = CacheMinSizes(extData.CellGroup3, true);
489489

490-
MeasureCellsGroup(extData.CellGroup2, innerAvailableSize, false, true);
490+
MeasureCellsGroup(extData.CellGroup2, false, true);
491491

492492
do
493493
{
@@ -498,20 +498,20 @@ protected override Size MeasureOverride(Size constraint)
498498
}
499499

500500
if (HasStarCellsU) { ResolveStar(DefinitionsU, innerAvailableSize.Width); }
501-
MeasureCellsGroup(extData.CellGroup3, innerAvailableSize, false, false);
501+
MeasureCellsGroup(extData.CellGroup3, false, false);
502502

503503
// Reset cached Group2Widths
504504
ApplyCachedMinSizes(group2MinSizes, false);
505505

506506
if (HasStarCellsV) { ResolveStar(DefinitionsV, innerAvailableSize.Height); }
507-
MeasureCellsGroup(extData.CellGroup2, innerAvailableSize, cnt == c_layoutLoopMaxCount, false, out hasDesiredSizeUChanged);
507+
MeasureCellsGroup(extData.CellGroup2, cnt == c_layoutLoopMaxCount, false, out hasDesiredSizeUChanged);
508508
}
509509
while (hasDesiredSizeUChanged && ++cnt <= c_layoutLoopMaxCount);
510510
}
511511
}
512512
}
513513

514-
MeasureCellsGroup(extData.CellGroup4, constraint, false, false);
514+
MeasureCellsGroup(extData.CellGroup4, false, false);
515515

516516
gridDesiredSize = new Size(
517517
CalculateDesiredSize(DefinitionsU) + ColumnSpacing * (DefinitionsU.Count - 1),
@@ -979,27 +979,23 @@ private void ApplyCachedMinSizes(double[] minSizes, bool isRows)
979979

980980
private void MeasureCellsGroup(
981981
int cellsHead,
982-
Size referenceSize,
983982
bool ignoreDesiredSizeU,
984983
bool forceInfinityV)
985984
{
986-
MeasureCellsGroup(cellsHead, referenceSize, ignoreDesiredSizeU, forceInfinityV, out _);
985+
MeasureCellsGroup(cellsHead, ignoreDesiredSizeU, forceInfinityV, out _);
987986
}
988987

989988
/// <summary>
990989
/// Measures one group of cells.
991990
/// </summary>
992991
/// <param name="cellsHead">Head index of the cells chain.</param>
993-
/// <param name="referenceSize">Reference size for spanned cells
994-
/// calculations.</param>
995992
/// <param name="ignoreDesiredSizeU">When "true" cells' desired
996993
/// width is not registered in columns.</param>
997994
/// <param name="forceInfinityV">Passed through to MeasureCell.
998995
/// When "true" cells' desired height is not registered in rows.</param>
999996
/// <param name="hasDesiredSizeUChanged">When the method exits, indicates whether the desired size has changed.</param>
1000997
private void MeasureCellsGroup(
1001998
int cellsHead,
1002-
Size referenceSize,
1003999
bool ignoreDesiredSizeU,
10041000
bool forceInfinityV,
10051001
out bool hasDesiredSizeUChanged)
@@ -1066,14 +1062,14 @@ private void MeasureCellsGroup(
10661062
foreach (DictionaryEntry e in spanStore)
10671063
{
10681064
SpanKey key = (SpanKey)e.Key;
1069-
double requestedSize = (double)e.Value!;
1065+
double desiredSize = (double)e.Value!;
10701066

10711067
EnsureMinSizeInDefinitionRange(
10721068
key.U ? DefinitionsU : DefinitionsV,
10731069
key.Start,
10741070
key.Count,
1075-
requestedSize,
1076-
key.U ? referenceSize.Width : referenceSize.Height);
1071+
key.U ? ColumnSpacing : RowSpacing,
1072+
desiredSize);
10771073
}
10781074
}
10791075
}
@@ -1193,8 +1189,8 @@ private static double GetMeasureSizeForRange(
11931189
measureSize +=
11941190
spacing +
11951191
(definitions[i].SizeType == LayoutTimeSizeType.Auto ?
1196-
definitions[i].MinSize :
1197-
definitions[i].MeasureSize);
1192+
definitions[i].MinSize :
1193+
definitions[i].MeasureSize);
11981194
} while (--i >= start);
11991195

12001196
return measureSize;
@@ -1228,20 +1224,23 @@ private static LayoutTimeSizeType GetLengthTypeForRange(
12281224
/// <summary>
12291225
/// Distributes min size back to definition array's range.
12301226
/// </summary>
1227+
/// <param name="definitions">Array of definitions to process.</param>
12311228
/// <param name="start">Start of the range.</param>
12321229
/// <param name="count">Number of items in the range.</param>
1233-
/// <param name="requestedSize">Minimum size that should "fit" into the definitions range.</param>
1234-
/// <param name="definitions">Definition array receiving distribution.</param>
1235-
/// <param name="percentReferenceSize">Size used to resolve percentages.</param>
1230+
/// <param name="spacing"><see cref="ColumnSpacing"/> or <see cref="RowSpacing"/></param>
1231+
/// <param name="desiredSize">Minimum size that should "fit" into the definitions range.</param>
12361232
private void EnsureMinSizeInDefinitionRange(
12371233
IReadOnlyList<DefinitionBase> definitions,
12381234
int start,
12391235
int count,
1240-
double requestedSize,
1241-
double percentReferenceSize)
1236+
double spacing,
1237+
double desiredSize)
12421238
{
12431239
Debug.Assert(1 < count && 0 <= start && (start + count) <= definitions.Count);
12441240

1241+
// The spacing between definitions that this element spans through must not be distributed
1242+
double requestedSize = Math.Max((desiredSize - spacing * (count - 1)), 0.0);
1243+
12451244
// avoid processing when asked to distribute "0"
12461245
if (!MathUtilities.IsZero(requestedSize))
12471246
{

tests/Avalonia.Controls.UnitTests/GridTests.cs

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Linq;
44
using Avalonia.UnitTests;
@@ -1773,7 +1773,7 @@ public void Grid_Controls_With_Spacing_With_Span()
17731773
ColumnDefinitions = ColumnDefinitions.Parse("20,20"),
17741774
Children =
17751775
{
1776-
new Border
1776+
new Border
17771777
{
17781778
Height = 100,
17791779
[Grid.ColumnSpanProperty] = 2
@@ -1787,6 +1787,119 @@ public void Grid_Controls_With_Spacing_With_Span()
17871787
Assert.Equal(new Rect(0, 0, 60, 100), target.Children[0].Bounds);
17881788
}
17891789

1790+
[Fact]
1791+
public void Grid_Controls_With_Spacing_With_Span_And_SharedSize()
1792+
{
1793+
using var app = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface);
1794+
1795+
var grid1 = new Grid()
1796+
{
1797+
[Grid.RowProperty] = 0,
1798+
RowDefinitions = RowDefinitions.Parse("Auto,*,Auto,Auto"),
1799+
ColumnDefinitions =
1800+
[
1801+
new ColumnDefinition(GridLength.Auto),
1802+
new ColumnDefinition(GridLength.Star),
1803+
new ColumnDefinition(GridLength.Auto),
1804+
new ColumnDefinition(GridLength.Auto)
1805+
{
1806+
SharedSizeGroup = "C3"
1807+
}
1808+
],
1809+
RowSpacing = 10,
1810+
ColumnSpacing = 10,
1811+
Children =
1812+
{
1813+
new ScrollViewer()
1814+
{
1815+
[Grid.RowProperty] = 0,
1816+
[Grid.ColumnProperty] = 0,
1817+
[Grid.RowSpanProperty] = 3,
1818+
[Grid.ColumnSpanProperty] = 3,
1819+
Content = new TextBlock()
1820+
{
1821+
Text = @"0: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1822+
1: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1823+
2: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1824+
3: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1825+
4: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1826+
5: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1827+
6: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1828+
7: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1829+
8: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890
1830+
9: 1234567890 1234567890 1234567890 1234567890 1234567890 1234567890"
1831+
}
1832+
},
1833+
new Button()
1834+
{
1835+
[Grid.RowProperty] = 3,
1836+
[Grid.ColumnProperty] = 0,
1837+
Width = 100,
1838+
Height = 40
1839+
},
1840+
new Button()
1841+
{
1842+
[Grid.RowProperty] = 3,
1843+
[Grid.ColumnProperty] = 2,
1844+
Width = 100,
1845+
Height = 40
1846+
},
1847+
new Button()
1848+
{
1849+
[Grid.RowProperty] = 0,
1850+
[Grid.ColumnProperty] = 3,
1851+
Width = 100,
1852+
Height = 40
1853+
},
1854+
new Button()
1855+
{
1856+
[Grid.RowProperty] = 2,
1857+
[Grid.ColumnProperty] = 3,
1858+
Width = 100,
1859+
Height = 40
1860+
}
1861+
}
1862+
};
1863+
1864+
var grid2 = new Grid()
1865+
{
1866+
[Grid.RowProperty] = 1,
1867+
ColumnDefinitions =
1868+
[
1869+
new ColumnDefinition(GridLength.Star),
1870+
new ColumnDefinition(GridLength.Auto)
1871+
{
1872+
SharedSizeGroup = "C3"
1873+
}
1874+
],
1875+
Children =
1876+
{
1877+
new TextBlock()
1878+
{
1879+
[Grid.ColumnProperty] = 1,
1880+
Height = 20,
1881+
Text="1234567890"
1882+
}
1883+
}
1884+
};
1885+
1886+
var root = new Grid()
1887+
{
1888+
[Grid.IsSharedSizeScopeProperty] = true,
1889+
RowDefinitions = RowDefinitions.Parse("*,Auto"),
1890+
RowSpacing = 10,
1891+
Margin = new Thickness(10)
1892+
};
1893+
root.Children.Add(grid1);
1894+
root.Children.Add(grid2);
1895+
root.Measure(new Size(550, 240));
1896+
root.Arrange(new Rect(new Point(), new Point(550, 240)));
1897+
1898+
Assert.Equal(new Rect(0, 0, 420, 140), grid1.Children[0].Bounds);
1899+
Assert.Equal(grid1.Children[4].Bounds.Left, grid2.Children[0].Bounds.Left);
1900+
Assert.Equal(grid1.Children[4].Bounds.Width, grid2.Children[0].Bounds.Width);
1901+
}
1902+
17901903
private class TestControl : Control
17911904
{
17921905
public Size MeasureSize { get; set; }

0 commit comments

Comments
 (0)