|
3 | 3 | // See the LICENSE file in the project root for more information.
|
4 | 4 |
|
5 | 5 | using System;
|
| 6 | +using System.Collections.Generic; |
| 7 | +using System.Linq; |
6 | 8 | using Windows.Foundation;
|
7 | 9 | using Windows.UI.Xaml;
|
8 | 10 | using Windows.UI.Xaml.Controls;
|
@@ -128,133 +130,130 @@ private static void LayoutPropertyChanged(DependencyObject d, DependencyProperty
|
128 | 130 | }
|
129 | 131 | }
|
130 | 132 |
|
| 133 | + private readonly List<Row> _rows = new List<Row>(); |
| 134 | + |
131 | 135 | /// <inheritdoc />
|
132 | 136 | protected override Size MeasureOverride(Size availableSize)
|
133 | 137 | {
|
134 |
| - availableSize.Width = availableSize.Width - Padding.Left - Padding.Right; |
135 |
| - availableSize.Height = availableSize.Height - Padding.Top - Padding.Bottom; |
136 |
| - var totalMeasure = UvMeasure.Zero; |
137 |
| - var parentMeasure = new UvMeasure(Orientation, availableSize.Width, availableSize.Height); |
138 |
| - var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); |
139 |
| - var lineMeasure = UvMeasure.Zero; |
140 |
| - |
| 138 | + var childAvailableSize = new Size( |
| 139 | + availableSize.Width - Padding.Left - Padding.Right, |
| 140 | + availableSize.Height - Padding.Top - Padding.Bottom); |
141 | 141 | foreach (var child in Children)
|
142 | 142 | {
|
143 |
| - child.Measure(availableSize); |
144 |
| - var currentMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); |
145 |
| - if (currentMeasure.U == 0) |
146 |
| - { |
147 |
| - continue; // ignore collapsed items |
148 |
| - } |
| 143 | + child.Measure(childAvailableSize); |
| 144 | + } |
149 | 145 |
|
150 |
| - // if this is the first item, do not add spacing. Spacing is added to the "left" |
151 |
| - double uChange = lineMeasure.U == 0 |
152 |
| - ? currentMeasure.U |
153 |
| - : currentMeasure.U + spacingMeasure.U; |
154 |
| - if (parentMeasure.U >= uChange + lineMeasure.U) |
155 |
| - { |
156 |
| - lineMeasure.U += uChange; |
157 |
| - lineMeasure.V = Math.Max(lineMeasure.V, currentMeasure.V); |
158 |
| - } |
159 |
| - else |
160 |
| - { |
161 |
| - // new line should be added |
162 |
| - // to get the max U to provide it correctly to ui width ex: ---| or -----| |
163 |
| - totalMeasure.U = Math.Max(lineMeasure.U, totalMeasure.U); |
164 |
| - totalMeasure.V += lineMeasure.V + spacingMeasure.V; |
| 146 | + var requiredSize = UpdateRows(availableSize); |
| 147 | + return requiredSize; |
| 148 | + } |
165 | 149 |
|
166 |
| - // if the next new row still can handle more controls |
167 |
| - if (parentMeasure.U > currentMeasure.U) |
168 |
| - { |
169 |
| - // set lineMeasure initial values to the currentMeasure to be calculated later on the new loop |
170 |
| - lineMeasure = currentMeasure; |
171 |
| - } |
| 150 | + /// <inheritdoc /> |
| 151 | + protected override Size ArrangeOverride(Size finalSize) |
| 152 | + { |
| 153 | + if ((Orientation == Orientation.Horizontal && finalSize.Width < DesiredSize.Width) || |
| 154 | + (Orientation == Orientation.Vertical && finalSize.Height < DesiredSize.Height)) |
| 155 | + { |
| 156 | + // We haven't received our desired size. We need to refresh the rows. |
| 157 | + UpdateRows(finalSize); |
| 158 | + } |
172 | 159 |
|
173 |
| - // the control will take one row alone |
174 |
| - else |
| 160 | + if (_rows.Count > 0) |
| 161 | + { |
| 162 | + // Now that we have all the data, we do the actual arrange pass |
| 163 | + var childIndex = 0; |
| 164 | + foreach (var row in _rows) |
| 165 | + { |
| 166 | + foreach (var rect in row.ChildrenRects) |
175 | 167 | {
|
176 |
| - // validate the new control measures |
177 |
| - totalMeasure.U = Math.Max(currentMeasure.U, totalMeasure.U); |
178 |
| - totalMeasure.V += currentMeasure.V; |
| 168 | + var child = Children[childIndex++]; |
| 169 | + var arrangeRect = new UvRect |
| 170 | + { |
| 171 | + Position = rect.Position, |
| 172 | + Size = new UvMeasure { U = rect.Size.U, V = row.Size.V }, |
| 173 | + }; |
179 | 174 |
|
180 |
| - // add new empty line |
181 |
| - lineMeasure = UvMeasure.Zero; |
| 175 | + var finalRect = arrangeRect.ToRect(Orientation); |
| 176 | + child.Arrange(finalRect); |
182 | 177 | }
|
183 | 178 | }
|
184 | 179 | }
|
185 | 180 |
|
186 |
| - // update value with the last line |
187 |
| - // if the last loop is (parentMeasure.U > currentMeasure.U + lineMeasure.U) the total isn't calculated then calculate it |
188 |
| - // if the last loop is (parentMeasure.U > currentMeasure.U) the currentMeasure isn't added to the total so add it here |
189 |
| - // for the last condition it is zeros so adding it will make no difference |
190 |
| - // this way is faster than an if condition in every loop for checking the last item |
191 |
| - totalMeasure.U = Math.Max(lineMeasure.U, totalMeasure.U); |
192 |
| - totalMeasure.V += lineMeasure.V; |
193 |
| - |
194 |
| - totalMeasure.U = Math.Ceiling(totalMeasure.U); |
195 |
| - |
196 |
| - return Orientation == Orientation.Horizontal ? new Size(totalMeasure.U, totalMeasure.V) : new Size(totalMeasure.V, totalMeasure.U); |
| 181 | + return finalSize; |
197 | 182 | }
|
198 | 183 |
|
199 |
| - /// <inheritdoc /> |
200 |
| - protected override Size ArrangeOverride(Size finalSize) |
| 184 | + private Size UpdateRows(Size availableSize) |
201 | 185 | {
|
202 |
| - if (Children.Count > 0) |
| 186 | + _rows.Clear(); |
| 187 | + |
| 188 | + var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top); |
| 189 | + var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom); |
| 190 | + |
| 191 | + if (Children.Count == 0) |
203 | 192 | {
|
204 |
| - var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height); |
205 |
| - var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); |
206 |
| - var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top); |
207 |
| - var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom); |
208 |
| - var position = new UvMeasure(Orientation, Padding.Left, Padding.Top); |
209 |
| - |
210 |
| - double currentV = 0; |
211 |
| - void Arrange(UIElement child, bool isLast = false) |
212 |
| - { |
213 |
| - var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height); |
214 |
| - if (desiredMeasure.U == 0) |
215 |
| - { |
216 |
| - return; // if an item is collapsed, avoid adding the spacing |
217 |
| - } |
| 193 | + var emptySize = paddingStart.Add(paddingEnd).ToSize(Orientation); |
| 194 | + return emptySize; |
| 195 | + } |
218 | 196 |
|
219 |
| - if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U) |
220 |
| - { |
221 |
| - // next row! |
222 |
| - position.U = paddingStart.U; |
223 |
| - position.V += currentV + spacingMeasure.V; |
224 |
| - currentV = 0; |
225 |
| - } |
| 197 | + var parentMeasure = new UvMeasure(Orientation, availableSize.Width, availableSize.Height); |
| 198 | + var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing); |
| 199 | + var position = new UvMeasure(Orientation, Padding.Left, Padding.Top); |
226 | 200 |
|
227 |
| - // Stretch the last item to fill the available space |
228 |
| - if (isLast) |
229 |
| - { |
230 |
| - desiredMeasure.U = parentMeasure.U - position.U; |
231 |
| - } |
| 201 | + var currentRow = new Row(new List<UvRect>(), default); |
| 202 | + var finalMeasure = new UvMeasure(Orientation, width: 0.0, height: 0.0); |
| 203 | + void Arrange(UIElement child, bool isLast = false) |
| 204 | + { |
| 205 | + var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize); |
| 206 | + if (desiredMeasure.U == 0) |
| 207 | + { |
| 208 | + return; // if an item is collapsed, avoid adding the spacing |
| 209 | + } |
232 | 210 |
|
233 |
| - // place the item |
234 |
| - if (Orientation == Orientation.Horizontal) |
235 |
| - { |
236 |
| - child.Arrange(new Rect(position.U, position.V, desiredMeasure.U, desiredMeasure.V)); |
237 |
| - } |
238 |
| - else |
239 |
| - { |
240 |
| - child.Arrange(new Rect(position.V, position.U, desiredMeasure.V, desiredMeasure.U)); |
241 |
| - } |
| 211 | + if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U) |
| 212 | + { |
| 213 | + // next row! |
| 214 | + position.U = paddingStart.U; |
| 215 | + position.V += currentRow.Size.V + spacingMeasure.V; |
242 | 216 |
|
243 |
| - // adjust the location for the next items |
244 |
| - position.U += desiredMeasure.U + spacingMeasure.U; |
245 |
| - currentV = Math.Max(desiredMeasure.V, currentV); |
| 217 | + _rows.Add(currentRow); |
| 218 | + currentRow = new Row(new List<UvRect>(), default); |
246 | 219 | }
|
247 | 220 |
|
248 |
| - var lastIndex = Children.Count - 1; |
249 |
| - for (var i = 0; i < lastIndex; i++) |
| 221 | + // Stretch the last item to fill the available space |
| 222 | + if (isLast) |
250 | 223 | {
|
251 |
| - Arrange(Children[i]); |
| 224 | + desiredMeasure.U = parentMeasure.U - position.U; |
252 | 225 | }
|
253 | 226 |
|
254 |
| - Arrange(Children[lastIndex], StretchChild == StretchChild.Last); |
| 227 | + currentRow.Add(position, desiredMeasure); |
| 228 | + |
| 229 | + // adjust the location for the next items |
| 230 | + position.U += desiredMeasure.U + spacingMeasure.U; |
| 231 | + finalMeasure.U = Math.Max(finalMeasure.U, position.U); |
255 | 232 | }
|
256 | 233 |
|
257 |
| - return finalSize; |
| 234 | + var lastIndex = Children.Count - 1; |
| 235 | + for (var i = 0; i < lastIndex; i++) |
| 236 | + { |
| 237 | + Arrange(Children[i]); |
| 238 | + } |
| 239 | + |
| 240 | + Arrange(Children[lastIndex], StretchChild == StretchChild.Last); |
| 241 | + if (currentRow.ChildrenRects.Count > 0) |
| 242 | + { |
| 243 | + _rows.Add(currentRow); |
| 244 | + } |
| 245 | + |
| 246 | + if (_rows.Count == 0) |
| 247 | + { |
| 248 | + var emptySize = paddingStart.Add(paddingEnd).ToSize(Orientation); |
| 249 | + return emptySize; |
| 250 | + } |
| 251 | + |
| 252 | + // Get max V here before computing final rect |
| 253 | + var lastRowRect = _rows.Last().Rect; |
| 254 | + finalMeasure.V = lastRowRect.Position.V + lastRowRect.Size.V; |
| 255 | + var finalRect = finalMeasure.Add(paddingEnd).ToSize(Orientation); |
| 256 | + return finalRect; |
258 | 257 | }
|
259 | 258 | }
|
260 | 259 | }
|
0 commit comments