Skip to content

Commit

Permalink
fix: make center with padding behave like figma
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert-Louis committed Nov 22, 2023
1 parent 9314b92 commit c9aee89
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 33 deletions.
48 changes: 48 additions & 0 deletions src/Uno.Toolkit.RuntimeTests/Tests/AutoLayoutTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using Windows.Foundation;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -156,7 +155,9 @@ protected override Size ArrangeOverride(Size finalSize)
haveMoreFilled,
spacing,
numberOfStackedChildren,
filledChildrenSizeAfterMaxSize);
filledChildrenSizeAfterMaxSize,
startPadding,
endPadding);

currentOffset += primaryAxisAlignmentOffset;

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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)]
Expand All @@ -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)
{
Expand All @@ -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)]
Expand Down

0 comments on commit c9aee89

Please sign in to comment.