diff --git a/src/Uno.Toolkit.RuntimeTests/Tests/AutoLayoutTest.cs b/src/Uno.Toolkit.RuntimeTests/Tests/AutoLayoutTest.cs index 94f4c8706..ffec3f43b 100644 --- a/src/Uno.Toolkit.RuntimeTests/Tests/AutoLayoutTest.cs +++ b/src/Uno.Toolkit.RuntimeTests/Tests/AutoLayoutTest.cs @@ -367,6 +367,54 @@ public async Task When_Space_between_With_AbsolutePosition(Orientation orientati } } + [TestMethod] + [RequiresFullWindow] + [DataRow(Orientation.Vertical, 80, 140, 125, 125)] + [DataRow(Orientation.Horizontal, 110, 110, 70, 180)] + public async Task When_Axis_Are_Center_With_No_Homogeneous_Padding(Orientation orientation, double rec1expectedY, double rec2expectedY, double rec1expectedX, double rec2expectedX) + { + var SUT = new AutoLayout() + { + Background = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0)), + Padding = new Thickness(150, 20, 100, 50), + Spacing = 10, + Width = 300, + Height = 300, + Orientation = orientation, + PrimaryAxisAlignment = AutoLayoutAlignment.Center, + }; + + var border1 = new Border() + { + Background = new SolidColorBrush(Color.FromArgb(255, 0, 0, 255)), + Width = 100, + Height = 50, + }; + + var border2 = new Border() + { + Background = new SolidColorBrush(Color.FromArgb(255, 0, 0, 255)), + Width = 100, + Height = 50, + }; + + AutoLayout.SetCounterAlignment(border1, AutoLayoutAlignment.Center); + AutoLayout.SetCounterAlignment(border2, AutoLayoutAlignment.Center); + + SUT.Children.Add(border1); + SUT.Children.Add(border2); + + await UnitTestUIContentHelperEx.SetContentAndWait(SUT); + + var border1Transform = border1.TransformToVisual(SUT).TransformPoint(new Windows.Foundation.Point(0, 0)); + var border2Transform = border2.TransformToVisual(SUT).TransformPoint(new Windows.Foundation.Point(0, 0)); + + Assert.AreEqual(rec1expectedY, border1Transform!.Y); + Assert.AreEqual(rec2expectedY, border2Transform!.Y); + Assert.AreEqual(rec1expectedX, border1Transform!.X); + Assert.AreEqual(rec2expectedX, border2Transform!.X); + } + [TestMethod] [RequiresFullWindow] public async Task When_Fixed_Dimensions_Padding_And_SpaceBetween_Horizontal() diff --git a/src/Uno.Toolkit.UI/Controls/AutoLayout/AutoLayout.Layouting.Arrange.cs b/src/Uno.Toolkit.UI/Controls/AutoLayout/AutoLayout.Layouting.Arrange.cs index 5e137250f..8272e82de 100644 --- a/src/Uno.Toolkit.UI/Controls/AutoLayout/AutoLayout.Layouting.Arrange.cs +++ b/src/Uno.Toolkit.UI/Controls/AutoLayout/AutoLayout.Layouting.Arrange.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using Windows.Foundation; @@ -36,6 +37,8 @@ protected override Size ArrangeOverride(Size finalSize) var numberOfStackedChildren = 0; var haveStartPadding = false; var haveEndPadding = false; + var startPadding = isHorizontal ? padding.Left : padding.Top; + var endPadding = isHorizontal ? padding.Right : padding.Bottom; if (_calculatedChildren is null || children.Count != _calculatedChildren.Length) { @@ -99,26 +102,22 @@ protected override Size ArrangeOverride(Size finalSize) break; case AutoLayoutAlignment.Center: var havePadding = atLeastOneFilledChild || justify == AutoLayoutJustify.SpaceBetween; - haveEndPadding = havePadding; haveStartPadding = havePadding; + haveEndPadding = havePadding; break; } - var startPadding = haveStartPadding - ? isHorizontal ? padding.Left : padding.Top - : 0d; - var endPadding = haveEndPadding - ? isHorizontal ? padding.Right : padding.Bottom - : 0d; + var applicableStartPadding = haveStartPadding ? isHorizontal ? padding.Left : padding.Top : 0; + var applicableEndPadding = haveEndPadding ? isHorizontal ? padding.Right : padding.Bottom : 0; - var totalPaddingSize = startPadding + endPadding; + var totalPaddingSize = applicableStartPadding + applicableEndPadding; // Available Size is the final size minus the border thickness and the padding var availableSizeForStackedChildren = finalSize.GetLength(orientation) - (borderThicknessLength + totalPaddingSize); EnsureZeroFloor(ref availableSizeForStackedChildren); // Start the offset at the border + start padding - var currentOffset = borderThickness.GetStartLength(orientation) + startPadding; + var currentOffset = borderThickness.GetStartLength(orientation) + applicableStartPadding; // Calculate the defined inter-element spacing size (if any, not taking care of SpaceBetween yet) var totalSpacingSize = spacing * (numberOfStackedChildren - 1); @@ -156,7 +155,9 @@ protected override Size ArrangeOverride(Size finalSize) haveMoreFilled, spacing, numberOfStackedChildren, - filledChildrenSizeAfterMaxSize); + filledChildrenSizeAfterMaxSize, + startPadding, + endPadding); currentOffset += primaryAxisAlignmentOffset; @@ -191,7 +192,7 @@ protected override Size ArrangeOverride(Size finalSize) ? Math.Min(child.MeasuredLength, filledChildrenSizeAfterMaxSize) : child.MeasuredLength; - var offsetRelativeToPadding = currentOffset - (startPadding + borderThicknessLength); + var offsetRelativeToPadding = currentOffset - (applicableStartPadding + borderThicknessLength); if (childLength > availableSizeForStackedChildren - offsetRelativeToPadding) { @@ -222,11 +223,13 @@ protected override Size ArrangeOverride(Size finalSize) ApplyMinMaxValues(child.Element, orientation, ref childSize); var counterAlignmentOffset = - ComputeCounterAlignmentOffset(counterAlignment, childSize.GetCounterLength(orientation), availableCounterLength, counterStartPadding, borderThickness.GetCounterStartLength(orientation)); + ComputeCounterAlignmentOffset(counterAlignment, childSize.GetCounterLength(orientation), availableCounterLength, padding, isHorizontal); + + var calculatedOffset = counterAlignmentOffset + counterStartPadding + borderThickness.GetCounterStartLength(orientation); var childOffsetPosition = new Point( - isHorizontal ? currentOffset : counterAlignmentOffset, - isHorizontal ? counterAlignmentOffset : currentOffset); + isHorizontal ? currentOffset : calculatedOffset, + isHorizontal ? calculatedOffset : currentOffset); // Arrange the child to its final position, determined by the calculated offset and size child.Element.Arrange(new Rect(childOffsetPosition, childSize)); @@ -287,19 +290,25 @@ private static double ComputeCounterAlignmentOffset( AutoLayoutAlignment autoLayoutAlignment, double childCounterLength, double availableCounterLength, - double counterStartPadding, - double counterBorderThickness) + Thickness padding, + bool isHorizontal) { - var alignmentOffsetSize = availableCounterLength - childCounterLength; - - var calculatedOffset = autoLayoutAlignment switch + switch (autoLayoutAlignment) { - AutoLayoutAlignment.End => alignmentOffsetSize, - AutoLayoutAlignment.Center when alignmentOffsetSize > 0 => alignmentOffsetSize / 2, - _ => 0 - }; - - return calculatedOffset + counterStartPadding + counterBorderThickness; + case AutoLayoutAlignment.Center: + var counterStartPadding = isHorizontal ? padding.Top : padding.Left; + var counterEndPadding = isHorizontal ? padding.Bottom : padding.Right; + var alignmentOffsetSize = availableCounterLength - (counterStartPadding + counterEndPadding); + var relativeOffset = Math.Abs(alignmentOffsetSize) / 2; + + return alignmentOffsetSize > 0 ? + (relativeOffset + counterStartPadding) - (childCounterLength / 2) : + relativeOffset + (availableCounterLength - counterEndPadding) - (childCounterLength / 2); + case AutoLayoutAlignment.End: + return availableCounterLength - childCounterLength; + default: + return 0; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -324,7 +333,9 @@ private static double PrimaryAxisAlignmentOffsetSize( bool haveMoreFilled, double spacing, int numberOfStackedChildren, - double filledChildrenSizeAfterMaxSize) + double filledChildrenSizeAfterMaxSize, + double startPadding, + double endPadding) { if (haveMoreFilled || autoLayoutAlignment is AutoLayoutAlignment.Start) { @@ -335,15 +346,22 @@ private static double PrimaryAxisAlignmentOffsetSize( var fillOverflow = filledChildrenSizeAfterMaxSize > 0 ? totalOfFillMaxSize : filledChildrenSizeAfterMaxSize; - var alignmentOffsetSize = availableSizeForStackedChildren - - (totalNonFilledStackedSize + totalSpacingSize + fillOverflow); + var occupiedSpace = totalNonFilledStackedSize + totalSpacingSize + fillOverflow; - return autoLayoutAlignment switch + switch (autoLayoutAlignment) { - AutoLayoutAlignment.End when (filledChildrenSizeAfterMaxSize == 0 || filledChildrenSizeAfterMaxSize > 0 && alignmentOffsetSize > 0 ) => alignmentOffsetSize, - AutoLayoutAlignment.Center when alignmentOffsetSize > 0 => alignmentOffsetSize / 2, - _ => 0 - }; + case AutoLayoutAlignment.Center: + var alignmentOffsetSize = availableSizeForStackedChildren - (startPadding + endPadding); + var relativeOffset = Math.Abs(alignmentOffsetSize) / 2; + + return alignmentOffsetSize > 0 ? + (relativeOffset + startPadding) - (occupiedSpace / 2) : + relativeOffset + (availableSizeForStackedChildren - endPadding) - (occupiedSpace / 2); + case AutoLayoutAlignment.End when filledChildrenSizeAfterMaxSize == 0 || filledChildrenSizeAfterMaxSize > 0 : + return availableSizeForStackedChildren - occupiedSpace; + default: + return 0; + } } [MethodImpl(MethodImplOptions.AggressiveInlining)]