Skip to content

Commit 030444f

Browse files
committed
update logic to reuse the computation result
1 parent cf81a75 commit 030444f

File tree

2 files changed

+94
-123
lines changed

2 files changed

+94
-123
lines changed

Microsoft.Toolkit.Uwp.UI.Controls/WrapPanel/WrapPanel.Data.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public UvMeasure(Orientation orientation, double width, double height)
4444

4545
public UvMeasure Add(double u, double v)
4646
=> new UvMeasure { U = U + u, V = V + v };
47+
48+
public Size ToSize(Orientation orientation)
49+
=> orientation == Orientation.Horizontal ? new Size(U, V) : new Size(V, U);
4750
}
4851

4952
private struct UvRect
@@ -52,18 +55,12 @@ private struct UvRect
5255

5356
public UvMeasure Size { get; set; }
5457

55-
public Rect ToRect(Orientation orientation)
58+
public Rect ToRect(Orientation orientation) => orientation switch
5659
{
57-
switch (orientation)
58-
{
59-
case Orientation.Vertical:
60-
return new Rect(Position.V, Position.U, Size.V, Size.U);
61-
case Orientation.Horizontal:
62-
return new Rect(Position.U, Position.V, Size.U, Size.V);
63-
default:
64-
throw new NotSupportedException();
65-
}
66-
}
60+
Orientation.Vertical => new Rect(Position.V, Position.U, Size.V, Size.U),
61+
Orientation.Horizontal => new Rect(Position.U, Position.V, Size.U, Size.V),
62+
_ => throw new NotSupportedException(),
63+
};
6764
}
6865

6966
private struct Row
@@ -84,6 +81,10 @@ public Row(List<UvRect> childrenRects, UvMeasure size)
8481
/// </summary>
8582
public UvMeasure Size => _rowSize;
8683

84+
public UvRect Rect => _childrenRects.Count > 0 ?
85+
new UvRect { Position = _childrenRects[0].Position, Size = Size } :
86+
new UvRect { Position = UvMeasure.Zero, Size = Size };
87+
8788
public void Add(UvMeasure position, UvMeasure size)
8889
{
8990
_childrenRects.Add(new UvRect { Position = position, Size = size });

Microsoft.Toolkit.Uwp.UI.Controls/WrapPanel/WrapPanel.cs

Lines changed: 82 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using System;
65
using System.Collections.Generic;
6+
using System.Linq;
77
using Windows.Foundation;
88
using Windows.UI.Xaml;
99
using Windows.UI.Xaml.Controls;
@@ -129,135 +129,37 @@ private static void LayoutPropertyChanged(DependencyObject d, DependencyProperty
129129
}
130130
}
131131

132+
private readonly List<Row> _rows = new List<Row>();
133+
132134
/// <inheritdoc />
133135
protected override Size MeasureOverride(Size availableSize)
134136
{
135-
availableSize.Width = availableSize.Width - Padding.Left - Padding.Right;
136-
availableSize.Height = availableSize.Height - Padding.Top - Padding.Bottom;
137-
var totalMeasure = UvMeasure.Zero;
138-
var parentMeasure = new UvMeasure(Orientation, availableSize.Width, availableSize.Height);
139-
var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
140-
var lineMeasure = UvMeasure.Zero;
141-
137+
var childAvailableSize = new Size(
138+
availableSize.Width - Padding.Left - Padding.Right,
139+
availableSize.Height - Padding.Top - Padding.Bottom);
142140
foreach (var child in Children)
143141
{
144-
child.Measure(availableSize);
145-
var currentMeasure = new UvMeasure(Orientation, child.DesiredSize);
146-
if (currentMeasure.U == 0)
147-
{
148-
continue; // ignore collapsed items
149-
}
150-
151-
// if this is the first item, do not add spacing. Spacing is added to the "left"
152-
double uChange = lineMeasure.U == 0
153-
? currentMeasure.U
154-
: currentMeasure.U + spacingMeasure.U;
155-
if (parentMeasure.U >= uChange + lineMeasure.U)
156-
{
157-
lineMeasure.U += uChange;
158-
lineMeasure.V = Math.Max(lineMeasure.V, currentMeasure.V);
159-
}
160-
else
161-
{
162-
// new line should be added
163-
// to get the max U to provide it correctly to ui width ex: ---| or -----|
164-
totalMeasure.U = Math.Max(lineMeasure.U, totalMeasure.U);
165-
totalMeasure.V += lineMeasure.V + spacingMeasure.V;
166-
167-
// if the next new row still can handle more controls
168-
if (parentMeasure.U > currentMeasure.U)
169-
{
170-
// set lineMeasure initial values to the currentMeasure to be calculated later on the new loop
171-
lineMeasure = currentMeasure;
172-
}
173-
174-
// the control will take one row alone
175-
else
176-
{
177-
// validate the new control measures
178-
totalMeasure.U = Math.Max(currentMeasure.U, totalMeasure.U);
179-
totalMeasure.V += currentMeasure.V;
180-
181-
// add new empty line
182-
lineMeasure = UvMeasure.Zero;
183-
}
184-
}
142+
child.Measure(childAvailableSize);
185143
}
186144

187-
// update value with the last line
188-
// if the last loop is (parentMeasure.U > currentMeasure.U + lineMeasure.U) the total isn't calculated then calculate it
189-
// if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here
190-
// for the last condition it is zeros so adding it will make no difference
191-
// this way is faster than an if condition in every loop for checking the last item
192-
totalMeasure.U = Math.Max(lineMeasure.U, totalMeasure.U);
193-
totalMeasure.V += lineMeasure.V;
194-
195-
totalMeasure.U = Math.Ceiling(totalMeasure.U);
196-
197-
return Orientation == Orientation.Horizontal ? new Size(totalMeasure.U, totalMeasure.V) : new Size(totalMeasure.V, totalMeasure.U);
145+
var requiredSize = UpdateRows(availableSize);
146+
return requiredSize;
198147
}
199148

200149
/// <inheritdoc />
201150
protected override Size ArrangeOverride(Size finalSize)
202151
{
203-
var rows = new List<Row>();
204-
if (Children.Count > 0)
152+
if (finalSize != DesiredSize)
205153
{
206-
var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
207-
var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
208-
var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top);
209-
var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom);
210-
var position = new UvMeasure(Orientation, Padding.Left, Padding.Top);
211-
212-
var currentRow = new Row(new List<UvRect>(), default);
213-
void Arrange(UIElement child, bool isLast = false)
214-
{
215-
var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize);
216-
if (desiredMeasure.U == 0)
217-
{
218-
return; // if an item is collapsed, avoid adding the spacing
219-
}
220-
221-
if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U)
222-
{
223-
// next row!
224-
position.U = paddingStart.U;
225-
position.V += currentRow.Size.V + spacingMeasure.V;
226-
227-
rows.Add(currentRow);
228-
currentRow = new Row(new List<UvRect>(), default);
229-
}
230-
231-
// Stretch the last item to fill the available space
232-
if (isLast)
233-
{
234-
desiredMeasure.U = parentMeasure.U - position.U;
235-
}
236-
237-
currentRow.Add(position, desiredMeasure);
238-
239-
// adjust the location for the next items
240-
position.U += desiredMeasure.U + spacingMeasure.U;
241-
}
242-
243-
var lastIndex = Children.Count - 1;
244-
for (var i = 0; i < lastIndex; i++)
245-
{
246-
Arrange(Children[i]);
247-
}
248-
249-
Arrange(Children[lastIndex], StretchChild == StretchChild.Last);
250-
if (currentRow.ChildrenRects.Count > 0)
251-
{
252-
rows.Add(currentRow);
253-
}
154+
// We haven't received our desired size. We need to refresh the rows.
155+
finalSize = UpdateRows(finalSize);
254156
}
255157

256-
if (rows.Count > 0)
158+
if (_rows.Count > 0)
257159
{
258160
// Now that we have all the data, we do the actual arrange pass
259161
var childIndex = 0;
260-
foreach (var row in rows)
162+
foreach (var row in _rows)
261163
{
262164
foreach (var rect in row.ChildrenRects)
263165
{
@@ -276,5 +178,73 @@ void Arrange(UIElement child, bool isLast = false)
276178

277179
return finalSize;
278180
}
181+
182+
private Size UpdateRows(Size finalSize)
183+
{
184+
_rows.Clear();
185+
if (Children.Count == 0)
186+
{
187+
return Size.Empty;
188+
}
189+
190+
var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
191+
var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
192+
var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top);
193+
var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom);
194+
var position = new UvMeasure(Orientation, Padding.Left, Padding.Top);
195+
196+
var currentRow = new Row(new List<UvRect>(), default);
197+
void Arrange(UIElement child, bool isLast = false)
198+
{
199+
var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize);
200+
if (desiredMeasure.U == 0)
201+
{
202+
return; // if an item is collapsed, avoid adding the spacing
203+
}
204+
205+
if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U)
206+
{
207+
// next row!
208+
position.U = paddingStart.U;
209+
position.V += currentRow.Size.V + spacingMeasure.V;
210+
211+
_rows.Add(currentRow);
212+
currentRow = new Row(new List<UvRect>(), default);
213+
}
214+
215+
// Stretch the last item to fill the available space
216+
if (isLast)
217+
{
218+
desiredMeasure.U = parentMeasure.U - position.U;
219+
}
220+
221+
currentRow.Add(position, desiredMeasure);
222+
223+
// adjust the location for the next items
224+
position.U += desiredMeasure.U + spacingMeasure.U;
225+
}
226+
227+
var lastIndex = Children.Count - 1;
228+
for (var i = 0; i < lastIndex; i++)
229+
{
230+
Arrange(Children[i]);
231+
}
232+
233+
Arrange(Children[lastIndex], StretchChild == StretchChild.Last);
234+
if (currentRow.ChildrenRects.Count > 0)
235+
{
236+
_rows.Add(currentRow);
237+
}
238+
239+
if (_rows.Count == 0)
240+
{
241+
return Size.Empty;
242+
}
243+
244+
var lastRowRect = _rows.Last().Rect.ToRect(Orientation);
245+
return new Size(
246+
lastRowRect.Bottom + Padding.Bottom,
247+
lastRowRect.Right + Padding.Right);
248+
}
279249
}
280250
}

0 commit comments

Comments
 (0)