From 1cf93ad393540cd81383708fbc4e16781765f932 Mon Sep 17 00:00:00 2001
From: Kermalis <29823718+Kermalis@users.noreply.github.com>
Date: Tue, 17 Sep 2019 23:04:12 -0400
Subject: [PATCH 1/4] Add ItemWidth and ItemHeight properties to WrapPanel
(with unit tests)
---
src/Avalonia.Controls/WrapPanel.cs | 198 +++++++++++-------
.../WrapPanelTests.cs | 23 ++
2 files changed, 150 insertions(+), 71 deletions(-)
diff --git a/src/Avalonia.Controls/WrapPanel.cs b/src/Avalonia.Controls/WrapPanel.cs
index 3acf341c35..418a59b64e 100644
--- a/src/Avalonia.Controls/WrapPanel.cs
+++ b/src/Avalonia.Controls/WrapPanel.cs
@@ -15,7 +15,7 @@ namespace Avalonia.Controls
/// Positions child elements in sequential position from left to right,
/// breaking content to the next line at the edge of the containing box.
/// Subsequent ordering happens sequentially from top to bottom or from right to left,
- /// depending on the value of the Orientation property.
+ /// depending on the value of the property.
///
public class WrapPanel : Panel, INavigableContainer
{
@@ -25,6 +25,18 @@ namespace Avalonia.Controls
public static readonly StyledProperty OrientationProperty =
AvaloniaProperty.Register(nameof(Orientation), defaultValue: Orientation.Horizontal);
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty ItemWidthProperty =
+ AvaloniaProperty.Register(nameof(ItemWidth), double.NaN);
+
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty ItemHeightProperty =
+ AvaloniaProperty.Register(nameof(ItemHeight), double.NaN);
+
///
/// Initializes static members of the class.
///
@@ -42,6 +54,24 @@ namespace Avalonia.Controls
set { SetValue(OrientationProperty, value); }
}
+ ///
+ /// Gets or sets the width of all items in the WrapPanel.
+ ///
+ public double ItemWidth
+ {
+ get { return GetValue(ItemWidthProperty); }
+ set { SetValue(ItemWidthProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the height of all items in the WrapPanel.
+ ///
+ public double ItemHeight
+ {
+ get { return GetValue(ItemHeightProperty); }
+ set { SetValue(ItemHeightProperty, value); }
+ }
+
///
/// Gets the next control in the specified direction.
///
@@ -51,7 +81,9 @@ namespace Avalonia.Controls
/// The control.
IInputElement INavigableContainer.GetControl(NavigationDirection direction, IInputElement from, bool wrap)
{
- var horiz = Orientation == Orientation.Horizontal;
+ var orientation = Orientation;
+ var children = Children;
+ bool horiz = orientation == Orientation.Horizontal;
int index = Children.IndexOf((IControl)from);
switch (direction)
@@ -60,7 +92,7 @@ namespace Avalonia.Controls
index = 0;
break;
case NavigationDirection.Last:
- index = Children.Count - 1;
+ index = children.Count - 1;
break;
case NavigationDirection.Next:
++index;
@@ -82,9 +114,9 @@ namespace Avalonia.Controls
break;
}
- if (index >= 0 && index < Children.Count)
+ if (index >= 0 && index < children.Count)
{
- return Children[index];
+ return children[index];
}
else
{
@@ -95,40 +127,51 @@ namespace Avalonia.Controls
///
protected override Size MeasureOverride(Size constraint)
{
- var curLineSize = new UVSize(Orientation);
- var panelSize = new UVSize(Orientation);
- var uvConstraint = new UVSize(Orientation, constraint.Width, constraint.Height);
-
- var childConstraint = new Size(constraint.Width, constraint.Height);
-
- for (int i = 0, count = Children.Count; i < count; i++)
+ double itemWidth = ItemWidth;
+ double itemHeight = ItemHeight;
+ var orientation = Orientation;
+ var children = Children;
+ var curLineSize = new UVSize(orientation);
+ var panelSize = new UVSize(orientation);
+ var uvConstraint = new UVSize(orientation, constraint.Width, constraint.Height);
+ bool itemWidthSet = !double.IsNaN(itemWidth);
+ bool itemHeightSet = !double.IsNaN(itemHeight);
+
+ var childConstraint = new Size(
+ itemWidthSet ? itemWidth : constraint.Width,
+ itemHeightSet ? itemHeight : constraint.Height);
+
+ for (int i = 0, count = children.Count; i < count; i++)
{
- var child = Children[i];
- if (child == null) continue;
-
- //Flow passes its own constrint to children
- child.Measure(childConstraint);
-
- //this is the size of the child in UV space
- var sz = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
-
- if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) //need to switch to another line
+ var child = children[i];
+ if (child != null)
{
- panelSize.U = Max(curLineSize.U, panelSize.U);
- panelSize.V += curLineSize.V;
- curLineSize = sz;
+ //Flow passes its own constrint to children
+ child.Measure(childConstraint);
+
+ //this is the size of the child in UV space
+ var sz = new UVSize(orientation,
+ itemWidthSet ? itemWidth : child.DesiredSize.Width,
+ itemHeightSet ? itemHeight : child.DesiredSize.Height);
- if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) //the element is wider then the constrint - give it a separate line
+ if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) //need to switch to another line
{
- panelSize.U = Max(sz.U, panelSize.U);
- panelSize.V += sz.V;
- curLineSize = new UVSize(Orientation);
+ panelSize.U = Max(curLineSize.U, panelSize.U);
+ panelSize.V += curLineSize.V;
+ curLineSize = sz;
+
+ if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) //the element is wider then the constrint - give it a separate line
+ {
+ panelSize.U = Max(sz.U, panelSize.U);
+ panelSize.V += sz.V;
+ curLineSize = new UVSize(orientation);
+ }
+ }
+ else //continue to accumulate a line
+ {
+ curLineSize.U += sz.U;
+ curLineSize.V = Max(sz.V, curLineSize.V);
}
- }
- else //continue to accumulate a line
- {
- curLineSize.U += sz.U;
- curLineSize.V = Max(sz.V, curLineSize.V);
}
}
@@ -143,68 +186,81 @@ namespace Avalonia.Controls
///
protected override Size ArrangeOverride(Size finalSize)
{
+ double itemWidth = ItemWidth;
+ double itemHeight = ItemHeight;
+ var orientation = Orientation;
+ var children = Children;
int firstInLine = 0;
double accumulatedV = 0;
- UVSize curLineSize = new UVSize(Orientation);
- UVSize uvFinalSize = new UVSize(Orientation, finalSize.Width, finalSize.Height);
-
- for (int i = 0; i < Children.Count; i++)
+ double itemU = orientation == Orientation.Horizontal ? itemWidth : itemHeight;
+ var curLineSize = new UVSize(orientation);
+ var uvFinalSize = new UVSize(orientation, finalSize.Width, finalSize.Height);
+ bool itemWidthSet = !double.IsNaN(itemWidth);
+ bool itemHeightSet = !double.IsNaN(itemHeight);
+ bool useItemU = orientation == Orientation.Horizontal ? itemWidthSet : itemHeightSet;
+
+ for (int i = 0; i < children.Count; i++)
{
- var child = Children[i];
- if (child == null) continue;
+ var child = children[i];
+ if (child != null)
+ {
+ var sz = new UVSize(orientation,
+ itemWidthSet ? itemWidth : child.DesiredSize.Width,
+ itemHeightSet ? itemHeight : child.DesiredSize.Height);
- var sz = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
+ if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) //need to switch to another line
+ {
+ ArrangeLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU);
- if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) //need to switch to another line
- {
- arrangeLine(accumulatedV, curLineSize.V, firstInLine, i);
+ accumulatedV += curLineSize.V;
+ curLineSize = sz;
- accumulatedV += curLineSize.V;
- curLineSize = sz;
+ if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) //the element is wider then the constraint - give it a separate line
+ {
+ //switch to next line which only contain one element
+ ArrangeLine(accumulatedV, sz.V, i, ++i, useItemU, itemU);
- if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) //the element is wider then the constraint - give it a separate line
+ accumulatedV += sz.V;
+ curLineSize = new UVSize(orientation);
+ }
+ firstInLine = i;
+ }
+ else //continue to accumulate a line
{
- //switch to next line which only contain one element
- arrangeLine(accumulatedV, sz.V, i, ++i);
-
- accumulatedV += sz.V;
- curLineSize = new UVSize(Orientation);
+ curLineSize.U += sz.U;
+ curLineSize.V = Max(sz.V, curLineSize.V);
}
- firstInLine = i;
- }
- else //continue to accumulate a line
- {
- curLineSize.U += sz.U;
- curLineSize.V = Max(sz.V, curLineSize.V);
}
}
//arrange the last line, if any
- if (firstInLine < Children.Count)
+ if (firstInLine < children.Count)
{
- arrangeLine(accumulatedV, curLineSize.V, firstInLine, Children.Count);
+ ArrangeLine(accumulatedV, curLineSize.V, firstInLine, children.Count, useItemU, itemU);
}
return finalSize;
}
- private void arrangeLine(double v, double lineV, int start, int end)
+ private void ArrangeLine(double v, double lineV, int start, int end, bool useItemU, double itemU)
{
+ var orientation = Orientation;
+ var children = Children;
double u = 0;
- bool isHorizontal = (Orientation == Orientation.Horizontal);
+ bool isHorizontal = orientation == Orientation.Horizontal;
for (int i = start; i < end; i++)
{
- var child = Children[i];
+ var child = children[i];
if (child != null)
{
- UVSize childSize = new UVSize(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
- double layoutSlotU = childSize.U;
+ var childSize = new UVSize(orientation, child.DesiredSize.Width, child.DesiredSize.Height);
+ double layoutSlotU = useItemU ? itemU : childSize.U;
child.Arrange(new Rect(
- (isHorizontal ? u : v),
- (isHorizontal ? v : u),
- (isHorizontal ? layoutSlotU : lineV),
- (isHorizontal ? lineV : layoutSlotU)));
+ isHorizontal ? u : v,
+ isHorizontal ? v : u,
+ isHorizontal ? layoutSlotU : lineV,
+ isHorizontal ? lineV : layoutSlotU));
u += layoutSlotU;
}
}
@@ -232,12 +288,12 @@ namespace Avalonia.Controls
internal double Width
{
- get { return (_orientation == Orientation.Horizontal ? U : V); }
+ get { return _orientation == Orientation.Horizontal ? U : V; }
set { if (_orientation == Orientation.Horizontal) U = value; else V = value; }
}
internal double Height
{
- get { return (_orientation == Orientation.Horizontal ? V : U); }
+ get { return _orientation == Orientation.Horizontal ? V : U; }
set { if (_orientation == Orientation.Horizontal) V = value; else U = value; }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs b/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
index a0511761e4..e0fa02814a 100644
--- a/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
@@ -93,5 +93,28 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new Rect(0, 0, 100, 50), target.Children[0].Bounds);
Assert.Equal(new Rect(100, 0, 100, 50), target.Children[1].Bounds);
}
+
+ [Fact]
+ public void Applies_ItemWidth_And_ItemHeight_Properties()
+ {
+ var target = new WrapPanel
+ {
+ Width = 50,
+ ItemWidth = 20,
+ ItemHeight = 15,
+ Children =
+ {
+ new Border(),
+ new Border { Width = 50, Height = 50 },
+ }
+ };
+
+ target.Measure(Size.Infinity);
+ target.Arrange(new Rect(target.DesiredSize));
+
+ Assert.Equal(new Size(50, 15), target.Bounds.Size);
+ Assert.Equal(new Rect(0, 0, 20, 15), target.Children[0].Bounds);
+ Assert.Equal(new Rect(20, 15, 20, 15), target.Children[1].Bounds);
+ }
}
}
From 9cc2d777addb1d46593d87e25baf4056b6e6658a Mon Sep 17 00:00:00 2001
From: Kermalis <29823718+Kermalis@users.noreply.github.com>
Date: Tue, 17 Sep 2019 23:56:47 -0400
Subject: [PATCH 2/4] Update WrapPanelTests.cs
---
.../WrapPanelTests.cs | 25 ++++++++++---------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs b/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
index e0fa02814a..149f723458 100644
--- a/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
@@ -97,24 +97,25 @@ namespace Avalonia.Controls.UnitTests
[Fact]
public void Applies_ItemWidth_And_ItemHeight_Properties()
{
- var target = new WrapPanel
- {
- Width = 50,
- ItemWidth = 20,
- ItemHeight = 15,
- Children =
- {
- new Border(),
- new Border { Width = 50, Height = 50 },
- }
- };
+ var target = new WrapPanel()
+ {
+ Orientation = Orientation.Horizontal,
+ Width = 50,
+ ItemWidth = 20,
+ ItemHeight = 15,
+ Children =
+ {
+ new Border(),
+ new Border { Width = 50, Height = 50 },
+ }
+ };
target.Measure(Size.Infinity);
target.Arrange(new Rect(target.DesiredSize));
Assert.Equal(new Size(50, 15), target.Bounds.Size);
Assert.Equal(new Rect(0, 0, 20, 15), target.Children[0].Bounds);
- Assert.Equal(new Rect(20, 15, 20, 15), target.Children[1].Bounds);
+ Assert.Equal(new Rect(20, 0, 20, 15), target.Children[1].Bounds);
}
}
}
From 1566c1a0689b6697149f229aee19dccde5794954 Mon Sep 17 00:00:00 2001
From: Kermalis <29823718+Kermalis@users.noreply.github.com>
Date: Wed, 18 Sep 2019 11:12:37 -0400
Subject: [PATCH 3/4] Update comments
---
src/Avalonia.Controls/WrapPanel.cs | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/Avalonia.Controls/WrapPanel.cs b/src/Avalonia.Controls/WrapPanel.cs
index 418a59b64e..7c88401615 100644
--- a/src/Avalonia.Controls/WrapPanel.cs
+++ b/src/Avalonia.Controls/WrapPanel.cs
@@ -146,28 +146,28 @@ namespace Avalonia.Controls
var child = children[i];
if (child != null)
{
- //Flow passes its own constrint to children
+ // Flow passes its own constraint to children
child.Measure(childConstraint);
- //this is the size of the child in UV space
+ // This is the size of the child in UV space
var sz = new UVSize(orientation,
itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height);
- if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) //need to switch to another line
+ if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvConstraint.U)) // Need to switch to another line
{
panelSize.U = Max(curLineSize.U, panelSize.U);
panelSize.V += curLineSize.V;
curLineSize = sz;
- if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) //the element is wider then the constrint - give it a separate line
+ if (MathUtilities.GreaterThan(sz.U, uvConstraint.U)) // The element is wider then the constraint - give it a separate line
{
panelSize.U = Max(sz.U, panelSize.U);
panelSize.V += sz.V;
curLineSize = new UVSize(orientation);
}
}
- else //continue to accumulate a line
+ else // Continue to accumulate a line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
@@ -175,11 +175,11 @@ namespace Avalonia.Controls
}
}
- //the last line size, if any should be added
+ // The last line size, if any should be added
panelSize.U = Max(curLineSize.U, panelSize.U);
panelSize.V += curLineSize.V;
- //go from UV space to W/H space
+ // Go from UV space to W/H space
return new Size(panelSize.Width, panelSize.Height);
}
@@ -208,16 +208,16 @@ namespace Avalonia.Controls
itemWidthSet ? itemWidth : child.DesiredSize.Width,
itemHeightSet ? itemHeight : child.DesiredSize.Height);
- if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) //need to switch to another line
+ if (MathUtilities.GreaterThan(curLineSize.U + sz.U, uvFinalSize.U)) // Need to switch to another line
{
ArrangeLine(accumulatedV, curLineSize.V, firstInLine, i, useItemU, itemU);
accumulatedV += curLineSize.V;
curLineSize = sz;
- if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) //the element is wider then the constraint - give it a separate line
+ if (MathUtilities.GreaterThan(sz.U, uvFinalSize.U)) // The element is wider then the constraint - give it a separate line
{
- //switch to next line which only contain one element
+ // Switch to next line which only contain one element
ArrangeLine(accumulatedV, sz.V, i, ++i, useItemU, itemU);
accumulatedV += sz.V;
@@ -225,7 +225,7 @@ namespace Avalonia.Controls
}
firstInLine = i;
}
- else //continue to accumulate a line
+ else // Continue to accumulate a line
{
curLineSize.U += sz.U;
curLineSize.V = Max(sz.V, curLineSize.V);
@@ -233,7 +233,7 @@ namespace Avalonia.Controls
}
}
- //arrange the last line, if any
+ // Arrange the last line, if any
if (firstInLine < children.Count)
{
ArrangeLine(accumulatedV, curLineSize.V, firstInLine, children.Count, useItemU, itemU);
From 2ee5a21dd7366fa98fbf350b07b18d5d164927e1 Mon Sep 17 00:00:00 2001
From: Kermalis <29823718+Kermalis@users.noreply.github.com>
Date: Sun, 22 Sep 2019 12:51:59 -0400
Subject: [PATCH 4/4] Remove broken test for now
An issue will be made after merging because it's unrelated
---
tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs b/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
index 149f723458..fd93df46b8 100644
--- a/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/WrapPanelTests.cs
@@ -106,7 +106,7 @@ namespace Avalonia.Controls.UnitTests
Children =
{
new Border(),
- new Border { Width = 50, Height = 50 },
+ new Border(),
}
};