Skip to content

Commit 25106dc

Browse files
committed
Added Orientation property to EqualPanel
1 parent 0bed1b7 commit 25106dc

File tree

1 file changed

+87
-25
lines changed

1 file changed

+87
-25
lines changed

components/Segmented/src/EqualPanel.cs

Lines changed: 87 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
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 Microsoft.UI.Xaml.Controls;
56
using System.Data;
67

78
namespace CommunityToolkit.WinUI.Controls;
@@ -14,15 +15,6 @@ public partial class EqualPanel : Panel
1415
private double _maxItemWidth = 0;
1516
private double _maxItemHeight = 0;
1617
private int _visibleItemsCount = 0;
17-
18-
/// <summary>
19-
/// Gets or sets the spacing between items.
20-
/// </summary>
21-
public double Spacing
22-
{
23-
get { return (double)GetValue(SpacingProperty); }
24-
set { SetValue(SpacingProperty, value); }
25-
}
2618

2719
/// <summary>
2820
/// Identifies the Spacing dependency property.
@@ -32,14 +24,42 @@ public double Spacing
3224
nameof(Spacing),
3325
typeof(double),
3426
typeof(EqualPanel),
35-
new PropertyMetadata(default(double), OnSpacingChanged));
27+
new PropertyMetadata(default(double), OnPropertyChanged));
28+
29+
/// <summary>
30+
/// Backing <see cref="DependencyProperty"/> for the <see cref="Orientation"/> property.
31+
/// </summary>
32+
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
33+
nameof(Orientation),
34+
typeof(Orientation),
35+
typeof(EqualPanel),
36+
new PropertyMetadata(default(Orientation), OnPropertyChanged));
37+
38+
/// <summary>
39+
/// Gets or sets the spacing between items.
40+
/// </summary>
41+
public double Spacing
42+
{
43+
get => (double)GetValue(SpacingProperty);
44+
set => SetValue(SpacingProperty, value);
45+
}
46+
47+
/// <summary>
48+
/// Gets or sets the panel orientation.
49+
/// </summary>
50+
public Orientation Orientation
51+
{
52+
get => (Orientation)GetValue(OrientationProperty);
53+
set => SetValue(OrientationProperty, value);
54+
}
3655

3756
/// <summary>
3857
/// Creates a new instance of the <see cref="EqualPanel"/> class.
3958
/// </summary>
4059
public EqualPanel()
4160
{
42-
RegisterPropertyChangedCallback(HorizontalAlignmentProperty, OnHorizontalAlignmentChanged);
61+
RegisterPropertyChangedCallback(HorizontalAlignmentProperty, OnAlignmentChanged);
62+
RegisterPropertyChangedCallback(VerticalAlignmentProperty, OnAlignmentChanged);
4363
}
4464

4565
/// <inheritdoc/>
@@ -60,19 +80,39 @@ protected override Size MeasureOverride(Size availableSize)
6080

6181
if (_visibleItemsCount > 0)
6282
{
63-
// Return equal widths based on the widest item
64-
// In very specific edge cases the AvailableWidth might be infinite resulting in a crash.
65-
if (HorizontalAlignment != HorizontalAlignment.Stretch || double.IsInfinity(availableSize.Width))
83+
bool stretch = Orientation switch
84+
{
85+
Orientation.Horizontal => HorizontalAlignment is HorizontalAlignment.Stretch && !double.IsInfinity(availableSize.Width),
86+
Orientation.Vertical or _ => VerticalAlignment is VerticalAlignment.Stretch && !double.IsInfinity(availableSize.Height),
87+
};
88+
89+
// Define XY coords
90+
double xSize = 0, ySize = 0;
91+
92+
// Define UV coords for orientation agnostic XY manipulation
93+
ref double uSize = ref SelectAxis(Orientation, ref xSize, ref ySize, true);
94+
ref double vSize = ref SelectAxis(Orientation, ref xSize, ref ySize, false);
95+
ref double maxItemU = ref SelectAxis(Orientation, ref _maxItemWidth, ref _maxItemHeight, true);
96+
ref double maxItemV = ref SelectAxis(Orientation, ref _maxItemWidth, ref _maxItemHeight, false);
97+
double availableU = Orientation is Orientation.Horizontal ? availableSize.Width : availableSize.Height;
98+
99+
if (stretch)
66100
{
67-
return new Size((_maxItemWidth * _visibleItemsCount) + (Spacing * (_visibleItemsCount - 1)), _maxItemHeight);
101+
// Adjust maxItemU to form equal rows/columns by available U space (adjust for spacing)
102+
double totalU = availableU - (Spacing * (_visibleItemsCount - 1));
103+
maxItemU = totalU / _visibleItemsCount;
104+
105+
// Set uSize/vSize for XY result contstruction
106+
uSize = availableU;
107+
vSize = maxItemV;
68108
}
69109
else
70110
{
71-
// Equal columns based on the available width, adjust for spacing
72-
double totalWidth = availableSize.Width - (Spacing * (_visibleItemsCount - 1));
73-
_maxItemWidth = totalWidth / _visibleItemsCount;
74-
return new Size(availableSize.Width, _maxItemHeight);
111+
uSize = (maxItemU * _visibleItemsCount) + (Spacing * (_visibleItemsCount - 1));
112+
vSize = maxItemV;
75113
}
114+
115+
return new Size(xSize, ySize);
76116
}
77117
else
78118
{
@@ -83,31 +123,53 @@ protected override Size MeasureOverride(Size availableSize)
83123
/// <inheritdoc/>
84124
protected override Size ArrangeOverride(Size finalSize)
85125
{
126+
// Define X and Y
86127
double x = 0;
128+
double y = 0;
87129

130+
// Define UV axis
131+
ref double u = ref x;
132+
ref double maxItemU = ref _maxItemWidth;
133+
double finalSizeU = finalSize.Width;
134+
if (Orientation is Orientation.Vertical)
135+
{
136+
u = ref y;
137+
maxItemU = ref _maxItemHeight;
138+
finalSizeU = finalSize.Height;
139+
}
140+
88141
// Check if there's more (little) width available - if so, set max item width to the maximum possible as we have an almost perfect height.
89-
if (finalSize.Width > _visibleItemsCount * _maxItemWidth + (Spacing * (_visibleItemsCount - 1)))
142+
if (finalSizeU > _visibleItemsCount * maxItemU + (Spacing * (_visibleItemsCount - 1)))
90143
{
91-
_maxItemWidth = (finalSize.Width - (Spacing * (_visibleItemsCount - 1))) / _visibleItemsCount;
144+
maxItemU = (finalSizeU - (Spacing * (_visibleItemsCount - 1))) / _visibleItemsCount;
92145
}
93146

94147
var elements = Children.Where(static e => e.Visibility == Visibility.Visible);
95148
foreach (var child in elements)
96149
{
97-
child.Arrange(new Rect(x, 0, _maxItemWidth, _maxItemHeight));
98-
x += _maxItemWidth + Spacing;
150+
// NOTE: The arrange method is still in X/Y coordinate system
151+
child.Arrange(new Rect(x, y, _maxItemWidth, _maxItemHeight));
152+
u += maxItemU + Spacing;
99153
}
100154
return finalSize;
101155
}
102156

103-
private void OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp)
157+
private void OnAlignmentChanged(DependencyObject sender, DependencyProperty dp)
104158
{
105159
InvalidateMeasure();
106160
}
107161

108-
private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
162+
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
109163
{
110164
var panel = (EqualPanel)d;
111165
panel.InvalidateMeasure();
112166
}
167+
168+
private static ref double SelectAxis(Orientation orientation, ref double x, ref double y, bool u)
169+
{
170+
if ((orientation is Orientation.Horizontal && u) || (orientation is Orientation.Vertical && !u))
171+
return ref x;
172+
else
173+
return ref y;
174+
}
113175
}

0 commit comments

Comments
 (0)