Skip to content

Commit e512d6c

Browse files
committed
Changed ItemsJustification to an enum
1 parent 6af1a89 commit e512d6c

9 files changed

+183
-39
lines changed

components/WrapPanel2/samples/WrapPanel2BasicSample.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
Grid.Row="1"
4343
HorizontalAlignment="{x:Bind LayoutHorizontalAlignment, Mode=OneWay}"
4444
VerticalAlignment="{x:Bind LayoutVerticalAlignment, Mode=OneWay}"
45-
ItemJustification="{x:Bind ItemJustification, Mode=OneWay}"
4645
ItemSpacing="{x:Bind ItemSpacing, Mode=OneWay}"
46+
ItemsJustification="{x:Bind local:WrapPanel2BasicSample.ConvertStringToItemsJustification(LayoutItemsJustification), Mode=OneWay}"
4747
ItemsStretch="{x:Bind local:WrapPanel2BasicSample.ConvertStringToItemsStretch(LayoutItemsStretch), Mode=OneWay}"
4848
LineSpacing="{x:Bind LineSpacing, Mode=OneWay}"
4949
Orientation="{x:Bind local:WrapPanel2BasicSample.ConvertStringToOrientation(LayoutOrientation), Mode=OneWay}" />

components/WrapPanel2/samples/WrapPanel2BasicSample.xaml.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace WrapPanel2Experiment.Samples;
1414
[ToolkitSampleMultiChoiceOption("LayoutVerticalAlignment", "Top", "Center", "Bottom", "Stretch", Title = "Vertical Alignment")]
1515
[ToolkitSampleNumericOption("ItemSpacing", 8, 0, 16, Title = "Item Spacing")]
1616
[ToolkitSampleNumericOption("LineSpacing", 2, 0, 16, Title = "Line Spacing")]
17-
[ToolkitSampleBoolOption("ItemJustification", false, Title = "Item Justification")]
17+
[ToolkitSampleMultiChoiceOption("LayoutItemsJustification", "Automatic", "Start", "Center", "End", "SpaceAround", "SpaceBetween", "SpaceEvenly", Title = "Items Justification")]
1818
[ToolkitSampleMultiChoiceOption("LayoutItemsStretch", "None", "First", "Last", "Equal", "Proportional", Title = "Items Stretch")]
1919

2020
[ToolkitSample(id: nameof(WrapPanel2BasicSample), $"Basic demo of the {nameof(WrapPanel2)} with auto-sized items.", description: $"A sample showing every property of the {nameof(WrapPanel2)} panel.")]
@@ -53,6 +53,19 @@ public WrapPanel2BasicSample()
5353
_ => throw new System.NotImplementedException(),
5454
};
5555

56+
// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
57+
public static WrapPanelItemsJustification ConvertStringToItemsJustification(string itemsJustification) => itemsJustification switch
58+
{
59+
"Automatic" => WrapPanelItemsJustification.Automatic,
60+
"Start" => WrapPanelItemsJustification.Start,
61+
"Center" => WrapPanelItemsJustification.Center,
62+
"End" => WrapPanelItemsJustification.End,
63+
"SpaceAround" => WrapPanelItemsJustification.SpaceAround,
64+
"SpaceBetween" => WrapPanelItemsJustification.SpaceBetween,
65+
"SpaceEvenly" => WrapPanelItemsJustification.SpaceEvenly,
66+
_ => throw new System.NotImplementedException(),
67+
};
68+
5669
// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
5770
public static WrapPanelItemsStretch ConvertStringToItemsStretch(string stretchMethod) => stretchMethod switch
5871
{

components/WrapPanel2/samples/WrapPanel2MegaSample.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
Margin="16">
2525
<controls:WrapPanel2 HorizontalAlignment="{x:Bind LayoutHorizontalAlignment, Mode=OneWay}"
2626
VerticalAlignment="{x:Bind LayoutVerticalAlignment, Mode=OneWay}"
27-
ItemJustification="{x:Bind ItemJustification, Mode=OneWay}"
2827
ItemSpacing="{x:Bind ItemSpacing, Mode=OneWay}"
28+
ItemsJustification="{x:Bind local:WrapPanel2MegaSample.ConvertStringToItemsJustification(LayoutItemsJustification), Mode=OneWay}"
2929
ItemsStretch="{x:Bind local:WrapPanel2MegaSample.ConvertStringToItemsStretch(LayoutItemsStretch), Mode=OneWay}"
3030
LineSpacing="{x:Bind LineSpacing, Mode=OneWay}"
3131
Orientation="{x:Bind local:WrapPanel2MegaSample.ConvertStringToOrientation(LayoutOrientation), Mode=OneWay}">

components/WrapPanel2/samples/WrapPanel2MegaSample.xaml.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace WrapPanel2Experiment.Samples;
1414
[ToolkitSampleMultiChoiceOption("LayoutVerticalAlignment", "Top", "Center", "Bottom", "Stretch", Title = "Vertical Alignment")]
1515
[ToolkitSampleNumericOption("ItemSpacing", 8, 0, 16, Title = "Item Spacing")]
1616
[ToolkitSampleNumericOption("LineSpacing", 2, 0, 16, Title = "Line Spacing")]
17-
[ToolkitSampleBoolOption("ItemJustification", false, Title = "Item Justification")]
17+
[ToolkitSampleMultiChoiceOption("LayoutItemsJustification", "Automatic", "Start", "Center", "End", "SpaceAround", "SpaceBetween", "SpaceEvenly", Title = "Items Justification")]
1818
[ToolkitSampleMultiChoiceOption("LayoutItemsStretch", "None", "First", "Last", "Equal", "Proportional", Title = "Items Stretch")]
1919

2020
[ToolkitSample(id: nameof(WrapPanel2MegaSample), "Demo of all WrapPanel2 feature", description: $"A sample showing every property of the {nameof(WrapPanel2)} panel.")]
@@ -53,6 +53,19 @@ public WrapPanel2MegaSample()
5353
_ => throw new System.NotImplementedException(),
5454
};
5555

56+
// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
57+
public static WrapPanelItemsJustification ConvertStringToItemsJustification(string itemsJustification) => itemsJustification switch
58+
{
59+
"Automatic" => WrapPanelItemsJustification.Automatic,
60+
"Start" => WrapPanelItemsJustification.Start,
61+
"Center" => WrapPanelItemsJustification.Center,
62+
"End" => WrapPanelItemsJustification.End,
63+
"SpaceAround" => WrapPanelItemsJustification.SpaceAround,
64+
"SpaceBetween" => WrapPanelItemsJustification.SpaceBetween,
65+
"SpaceEvenly" => WrapPanelItemsJustification.SpaceEvenly,
66+
_ => throw new System.NotImplementedException(),
67+
};
68+
5669
// TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
5770
public static WrapPanelItemsStretch ConvertStringToItemsStretch(string stretchMethod) => stretchMethod switch
5871
{

components/WrapPanel2/src/WrapPanel2.Properties.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ public partial class WrapPanel2
4444
new PropertyMetadata(default(double), OnPropertyChanged));
4545

4646
/// <summary>
47-
/// Backing <see cref="DependencyProperty"/> for the <see cref="ItemJustification"/> property.
47+
/// Backing <see cref="DependencyProperty"/> for the <see cref="ItemsJustification"/> property.
4848
/// </summary>
49-
public static readonly DependencyProperty ItemJustificationProperty = DependencyProperty.Register(
50-
nameof(ItemJustification),
51-
typeof(bool),
49+
public static readonly DependencyProperty ItemsJustificationProperty = DependencyProperty.Register(
50+
nameof(ItemsJustification),
51+
typeof(WrapPanelItemsJustification),
5252
typeof(WrapPanel2),
5353
new PropertyMetadata(default(bool), OnPropertyChanged));
5454

@@ -74,7 +74,7 @@ public Orientation Orientation
7474
/// Gets or sets the spacing between items.
7575
/// </summary>
7676
/// <remarks>
77-
/// When <see cref="ItemJustification"/> is enabled and <see cref="ItemsStretch"/> is <see cref="WrapPanelItemsStretch.None"/>,
77+
/// When <see cref="ItemsJustification"/> is in a spacing mode and <see cref="ItemsStretch"/> is <see cref="WrapPanelItemsStretch.None"/>,
7878
/// this may instead be used as the minimum space between items, while the exact spacing is adjusted to ensure the items span from margin to margin.
7979
/// </remarks>
8080
public double ItemSpacing
@@ -98,14 +98,14 @@ public double LineSpacing
9898
/// <remarks>
9999
/// This will not apply on lines without star-sized items unless a <see cref="ItemsStretch"/> behavior is selected.
100100
/// </remarks>
101-
public bool ItemJustification
101+
public WrapPanelItemsJustification ItemsJustification
102102
{
103-
get => (bool)GetValue(ItemJustificationProperty);
104-
set => SetValue(ItemJustificationProperty, value);
103+
get => (WrapPanelItemsJustification)GetValue(ItemsJustificationProperty);
104+
set => SetValue(ItemsJustificationProperty, value);
105105
}
106106

107107
/// <summary>
108-
/// Gets or sets the method used to fill rows without a star-sized item when <see cref="ItemJustification"/> is enabled.
108+
/// Gets or sets the method used to fill rows without a star-sized item when <see cref="ItemsJustification"/> is in a spacing mode.
109109
/// </summary>
110110
public WrapPanelItemsStretch ItemsStretch
111111
{

components/WrapPanel2/src/WrapPanel2.Structs.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,26 @@ public RowSpec(GridLength layout, UVCoord desiredSize)
7474
/// </summary>
7575
public int ItemsCount { get; private set; }
7676

77-
public bool TryAdd(RowSpec addend, double spacing, double maxSize, bool equalStretching)
77+
/// <remarks>
78+
/// New size is only set if the size changes.
79+
/// Otherwise it will be 0.
80+
/// </remarks>
81+
public bool TryAdd(RowSpec addend, double spacing, double maxSize, WrapPanelItemsStretch stretching, WrapPanelItemsJustification justification)
7882
{
7983
// Check if adding the new spec would exceed the maximum size
8084
var sum = this + addend;
81-
if (sum.Measure(spacing, equalStretching) > maxSize)
85+
if (sum.Measure(spacing, stretching, justification) > maxSize)
8286
return false;
8387

8488
// Update the current spec to include the new spec
8589
this = sum;
8690
return true;
8791
}
8892

89-
public readonly double Measure(double spacing, bool equalStretching)
93+
public readonly double Measure(double spacing, WrapPanelItemsStretch stretching, WrapPanelItemsJustification justification)
9094
{
91-
var totalSpacing = (ItemsCount - 1) * spacing;
95+
var totalSpacing = GetTotalSpacing(ItemsCount, spacing, justification);
96+
var equalStretching = stretching is WrapPanelItemsStretch.Equal && IsSpacingJustified(justification);
9297

9398
// Handle equal-sized items child stretching.
9499
// Without this check, children might become scrunched in the arrange

components/WrapPanel2/src/WrapPanel2.cs

Lines changed: 88 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ protected override Size MeasureOverride(Size availableSize)
3131
return new Size(0, 0);
3232
}
3333

34-
// Adjusted measuring will be required if items justification is enabled and
35-
// ItemsStreching is set to Equal. Condense this into a bool here.
36-
bool equalStretching = ItemJustification && ItemsStretch is WrapPanelItemsStretch.Equal;
37-
3834
foreach (var child in elements)
3935
{
4036
// Measure the child's desired size and get layout
@@ -44,19 +40,20 @@ protected override Size MeasureOverride(Size availableSize)
4440

4541
// Attempt to add the child to the current row/column
4642
var spec = new RowSpec(layoutLength, uvDesiredSize);
47-
if (!currentRowSpec.TryAdd(spec, ItemSpacing, uvAvailableSize.U, equalStretching))
43+
if (!currentRowSpec.TryAdd(spec, ItemSpacing, uvAvailableSize.U, ItemsStretch, RealJustification))
4844
{
4945
// Could not add to current row/column
5046
// Start a new row/column
5147
_rowSpecs.Add(currentRowSpec);
52-
_longestRowSize = Math.Max(_longestRowSize, currentRowSpec.Measure(ItemSpacing, equalStretching));
48+
var newSize = currentRowSpec.Measure(ItemSpacing, ItemsStretch, RealJustification);
49+
_longestRowSize = Math.Max(_longestRowSize, newSize);
5350
currentRowSpec = spec;
5451
}
5552
}
5653

5754
// Add the final row/column
5855
_rowSpecs.Add(currentRowSpec);
59-
_longestRowSize = Math.Max(_longestRowSize, currentRowSpec.Measure(ItemSpacing, equalStretching));
56+
_longestRowSize = Math.Max(_longestRowSize, currentRowSpec.Measure(ItemSpacing, ItemsStretch, RealJustification));
6057

6158
// Calculate final desired size
6259
var uvSize = new UVCoord(0, 0, Orientation)
@@ -106,13 +103,13 @@ protected override Size ArrangeOverride(Size finalSize)
106103

107104
private void ArrangeRow(ref UVCoord pos, RowSpec row, UVCoord uvFinalSize, Queue<UIElement> childQueue)
108105
{
109-
var spacingTotalSize = ItemSpacing * (row.ItemsCount - 1);
106+
var spacingTotalSize = GetTotalSpacing(row.ItemsCount, ItemSpacing, RealJustification);
110107
var remainingSpace = uvFinalSize.U - row.ReservedSpace - spacingTotalSize;
111108
var portionSize = row.MinPortionSize;
112109

113110
// Determine if the desired alignment is stretched.
114111
// Or if fixed row lengths are in use.
115-
bool stretch = IsMainAxisStretch(uvFinalSize.U) || ItemJustification;
112+
bool stretch = IsMainAxisStretch(uvFinalSize.U) || JustifiedSpacing;
116113

117114
// Calculate portion size if stretching
118115
// Same logic applies for matching row lengths, since the size was determined during measure
@@ -124,17 +121,9 @@ private void ArrangeRow(ref UVCoord pos, RowSpec row, UVCoord uvFinalSize, Queue
124121
// Reset the starting U position
125122
pos.U = 0;
126123

127-
// Adjust the starting position if not stretching
128-
// Also do this if there are no star-sized items in the row/column and no forced streching is in use.
129-
if (!stretch || (row.PortionsSum is 0 && ItemsStretch is WrapPanelItemsStretch.None))
130-
{
131-
var rowSize = row.Measure(ItemSpacing, false);
132-
pos.U = GetStartByAlignment(GetAlignment(), rowSize, uvFinalSize.U);
133-
}
134-
135124
// Set a flag for if the row is being forced to stretch
136125
// Also declare a variable for the effective items spacing. This will be adjusted if needed for justification.
137-
bool forceStretch = ItemJustification && row.PortionsSum is 0 && ItemsStretch is not WrapPanelItemsStretch.None;
126+
bool forceStretch = JustifiedSpacing && row.PortionsSum is 0 && ItemsStretch is not WrapPanelItemsStretch.None;
138127
var itemSpacing = ItemSpacing;
139128

140129
// Setup portionSize for forced stretching
@@ -166,13 +155,33 @@ private void ArrangeRow(ref UVCoord pos, RowSpec row, UVCoord uvFinalSize, Queue
166155
_ => row.MinPortionSize,
167156
};
168157
}
169-
else if (ItemJustification && row.PortionsSum is 0)
158+
else if (JustifiedSpacing && row.PortionsSum is 0)
170159
{
171160
// If Item Justification is enabled and there's no proportional
172-
// Adjust the spacing between items to align items with the margins
173-
itemSpacing = (remainingSpace + spacingTotalSize) / (row.ItemsCount - 1);
161+
// Adjust the spacing between items according to the justification mode.
162+
var divisbleSpace = remainingSpace + spacingTotalSize;
163+
itemSpacing = RealJustification switch
164+
{
165+
WrapPanelItemsJustification.SpaceBetween => divisbleSpace / (row.ItemsCount - 1),
166+
WrapPanelItemsJustification.SpaceAround => divisbleSpace / row.ItemsCount,
167+
WrapPanelItemsJustification.SpaceEvenly => divisbleSpace / (row.ItemsCount + 1),
168+
_ => divisbleSpace / row.ItemsCount,
169+
};
174170
}
175171

172+
// Adjust the starting position
173+
var rowSize = row.Measure(ItemSpacing, ItemsStretch, RealJustification);
174+
pos.U = RealJustification switch
175+
{
176+
WrapPanelItemsJustification.SpaceAround => itemSpacing / 2,
177+
WrapPanelItemsJustification.SpaceBetween => 0,
178+
WrapPanelItemsJustification.SpaceEvenly => itemSpacing,
179+
180+
WrapPanelItemsJustification.Start or
181+
WrapPanelItemsJustification.Center or
182+
WrapPanelItemsJustification.End or _ => GetStartByAlignment(GetJustificationAlignment(), rowSize, uvFinalSize.U),
183+
};
184+
176185
// Arrange each child in the row/column
177186
for (int i = 0; i < row.ItemsCount; i++)
178187
{
@@ -312,12 +321,70 @@ private Alignment GetOffAlignment()
312321
};
313322
}
314323

324+
private Alignment GetJustificationAlignment()
325+
{
326+
return RealJustification switch
327+
{
328+
WrapPanelItemsJustification.Start => Alignment.Start,
329+
WrapPanelItemsJustification.Center => Alignment.Center,
330+
WrapPanelItemsJustification.End => Alignment.End,
331+
_ => Alignment.Stretch,
332+
};
333+
}
334+
315335
/// <summary>
316336
/// Determine if the desired alignment is stretched.
317337
/// Don't stretch if infinite space is available though. Attempting to divide infinite space will result in a crash.
318338
/// </summary>
319339
private bool IsMainAxisStretch(double availableSize) => GetAlignment() is Alignment.Stretch && !double.IsInfinity(availableSize);
320340

341+
/// <summary>
342+
/// Gets whether or not the <see cref="ItemsJustification"/> is adjusting spacing.
343+
/// </summary>
344+
private bool JustifiedSpacing => IsSpacingJustified(RealJustification);
345+
346+
/// <summary>
347+
/// Gets the <see cref="ItemsJustification"/> with the automatic option converted to the actual behavior.
348+
/// </summary>
349+
private WrapPanelItemsJustification RealJustification => ItemsJustification switch
350+
{
351+
WrapPanelItemsJustification.Automatic => GetAlignment() switch
352+
{
353+
Alignment.Start => WrapPanelItemsJustification.Start,
354+
Alignment.Center => WrapPanelItemsJustification.Center,
355+
Alignment.End => WrapPanelItemsJustification.End,
356+
_ => WrapPanelItemsJustification.SpaceBetween,
357+
},
358+
_ => ItemsJustification,
359+
};
360+
361+
private static bool IsSpacingJustified(WrapPanelItemsJustification justification) => justification switch
362+
{
363+
WrapPanelItemsJustification.Start or
364+
WrapPanelItemsJustification.Center or
365+
WrapPanelItemsJustification.End => false,
366+
367+
WrapPanelItemsJustification.SpaceAround or
368+
WrapPanelItemsJustification.SpaceBetween or
369+
WrapPanelItemsJustification.SpaceEvenly => true,
370+
371+
_ => false,
372+
};
373+
374+
private static double GetTotalSpacing(int itemCount, double itemsSpacing, WrapPanelItemsJustification justification)
375+
{
376+
return justification switch
377+
{
378+
WrapPanelItemsJustification.SpaceAround => itemCount * itemsSpacing,
379+
WrapPanelItemsJustification.SpaceEvenly => (itemCount + 1) * itemsSpacing,
380+
381+
WrapPanelItemsJustification.Start or
382+
WrapPanelItemsJustification.Center or
383+
WrapPanelItemsJustification.End or
384+
WrapPanelItemsJustification.SpaceBetween or _ => (itemCount - 1) * itemsSpacing,
385+
};
386+
}
387+
321388
private double GetChildSize(UIElement child)
322389
{
323390
var childLayout = GetLayoutLength(child);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace CommunityToolkit.WinUI.Controls;
6+
7+
/// <summary>
8+
/// Describes how items are arranged between the margins of the main axis in the <see cref="WrapPanel2"/>.
9+
/// </summary>
10+
public enum WrapPanelItemsJustification
11+
{
12+
/// <summary>
13+
/// Items will be arranged according to the control's alignment over the main axis.
14+
/// </summary>
15+
Automatic,
16+
17+
/// <summary>
18+
/// Items will be arranged starting aligned with starting margin of the line.
19+
/// </summary>
20+
Start,
21+
22+
/// <summary>
23+
/// Items will be arranged in the center of the line.
24+
/// </summary>
25+
Center,
26+
27+
/// <summary>
28+
/// Items will be arranged ending aligned with the ending margin of the line.
29+
/// </summary>
30+
End,
31+
32+
/// <summary>
33+
/// Items will be arranged with padding on both sides of each item, and half-sized padding against the margin.
34+
/// </summary>
35+
SpaceAround,
36+
37+
/// <summary>
38+
/// Items will be arranged with equal padding between all items, and no padding against the margins.
39+
/// </summary>
40+
SpaceBetween,
41+
42+
/// <summary>
43+
/// Items will be arranged with padding on both sides of each item, and full-sized padding against the margin.
44+
/// </summary>
45+
SpaceEvenly,
46+
}

components/WrapPanel2/src/WrapPanelItemsStretch.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public enum WrapPanelItemsStretch
1717
/// </summary>
1818
/// <remarks>
1919
/// Items with a Star-Sized <see cref="WrapPanel2.LayoutLengthProperty"/> will still stretch if the main-axis alignment
20-
/// is set to stretch or if <see cref="WrapPanel2.ItemJustification"/> is enabled.
20+
/// is set to stretch or if <see cref="WrapPanel2.ItemsJustification"/> is enabled.
2121
/// </remarks>
2222
None,
2323

0 commit comments

Comments
 (0)