Skip to content

Commit

Permalink
fix(autolayout): child.Measure with porper availableSizeForChild (#645)
Browse files Browse the repository at this point in the history
(cherry picked from commit 5430aef)

Co-authored-by: Robert-Louis Milin <milinmt@gmail.com>
  • Loading branch information
mergify[bot] and Robert-Louis committed Jul 12, 2023
1 parent 536c2df commit fc3ece3
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,6 @@ protected override Size ArrangeOverride(Size finalSize)
// Calculate the position of the child by applying the alignment instructions
var counterAlignment = GetCounterAlignment(child.Element);

var isPrimaryAlignmentStretch = GetPrimaryAlignment(child.Element) is AutoLayoutPrimaryAlignment.Stretch;
var isCounterAlignmentStretch = counterAlignment is AutoLayoutAlignment.Stretch;

if (child.Element is FrameworkElement frameworkElement)
{
UpdateCounterAlignmentToStretch(ref frameworkElement, isHorizontal, isPrimaryAlignmentStretch, isCounterAlignmentStretch);
}

var haveCounterStartPadding = counterAlignment is AutoLayoutAlignment.Stretch or AutoLayoutAlignment.Start;
var counterStartPadding = haveCounterStartPadding ? (isHorizontal ? padding.Top : padding.Left) : 0;

Expand Down Expand Up @@ -223,21 +215,6 @@ protected override Size ArrangeOverride(Size finalSize)
return finalSize;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void UpdateCounterAlignmentToStretch(ref FrameworkElement frameworkElement, bool isHorizontal, bool isPrimaryAlignmentStretch, bool isCounterAlignmentStretch)
{
if (isHorizontal)
{
frameworkElement.HorizontalAlignment = isPrimaryAlignmentStretch ? HorizontalAlignment.Stretch : frameworkElement.HorizontalAlignment;
frameworkElement.VerticalAlignment = isCounterAlignmentStretch ? VerticalAlignment.Stretch : frameworkElement.VerticalAlignment;
}
else
{
frameworkElement.VerticalAlignment = isPrimaryAlignmentStretch ? VerticalAlignment.Stretch : frameworkElement.VerticalAlignment;
frameworkElement.HorizontalAlignment = isCounterAlignmentStretch ? HorizontalAlignment.Stretch : frameworkElement.HorizontalAlignment;
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void ApplyMinMaxValues(UIElement element, Orientation orientation, ref Size desiredSize)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,28 @@ protected override Size MeasureOverride(Size availableSize)

// 2. Remove applicable padding and spacing from the remaining size
var paddingSize = Padding.GetLength(orientation);
var counterPaddingSize = Padding.GetCounterLength(orientation);
Decrement(ref remainingSize, paddingSize);

// 3. Measure fixed children
MeasureFixedChildren(orientation, availableCounterSize, ref remainingSize, ref desiredCounterSize);
MeasureFixedChildren(orientation, availableCounterSize, ref remainingSize, ref desiredCounterSize, counterPaddingSize);

// 4. Establish the total spacing size, if applicable
var totalSpacingSize = 0d;
if (numberOfStackedChildren > 0
&& justify != AutoLayoutJustify.SpaceBetween
&& spacing != 0
&& spacing < double.PositiveInfinity)
&& justify != AutoLayoutJustify.SpaceBetween
&& spacing != 0
&& spacing < double.PositiveInfinity)
{
totalSpacingSize = (numberOfStackedChildren - 1) * spacing;
Decrement(ref remainingSize, totalSpacingSize);
}

// 5. Calculate the size of Hug children
MeasureHugChildren(orientation, availableCounterSize, ref remainingSize, ref desiredCounterSize);
MeasureHugChildren(orientation, availableCounterSize, ref remainingSize, ref desiredCounterSize, counterPaddingSize);

// 6. Calculate the size of Filled children
MeasureFilledChildren(orientation, availableCounterSize, ref remainingSize, ref desiredCounterSize);
MeasureFilledChildren(orientation, availableCounterSize, ref remainingSize, ref desiredCounterSize, counterPaddingSize);

// 7. Measure independent children, independently of the remaining size
var independentDesiredSize = MeasureIndependentChildren(availableSize, borderThickness, orientation, ref desiredCounterSize);
Expand All @@ -74,17 +75,17 @@ protected override Size MeasureOverride(Size availableSize)
Size desiredSize;

if ((atLeastOneFilledChild
|| justify == AutoLayoutJustify.SpaceBetween)
&& remainingSize is > 0 and < double.PositiveInfinity)
|| justify == AutoLayoutJustify.SpaceBetween)
&& remainingSize is > 0 and < double.PositiveInfinity)
{
// 8a. Calculated the spacing size, when justify is SpaceBetween or there's at least one filled child

// We don't need to calculate the spacing since it's the remaining size
// and the final spacing will be calculated in the arrange pass.
desiredSize = orientation switch
{
Orientation.Horizontal => new Size(availableSize.Width, desiredCounterSize + Padding.GetCounterLength(orientation)),
Orientation.Vertical => new Size(desiredCounterSize + Padding.GetCounterLength(orientation), availableSize.Height),
Orientation.Horizontal => new Size(availableSize.Width, desiredCounterSize + counterPaddingSize),
Orientation.Vertical => new Size(desiredCounterSize + counterPaddingSize, availableSize.Height),
_ => throw new ArgumentOutOfRangeException(),
};
}
Expand All @@ -105,9 +106,9 @@ protected override Size MeasureOverride(Size availableSize)
{
Orientation.Horizontal => new Size(
width: desiredSizeInPrimaryOrientation + paddingSize,
height: desiredCounterSize + Padding.GetCounterLength(orientation)),
height: desiredCounterSize + counterPaddingSize),
Orientation.Vertical => new Size(
width: desiredCounterSize + Padding.GetCounterLength(orientation),
width: desiredCounterSize + counterPaddingSize,
height: desiredSizeInPrimaryOrientation + paddingSize),
_ => throw new ArgumentOutOfRangeException(),
};
Expand Down Expand Up @@ -204,7 +205,8 @@ private void ApplyMinMaxValues(ref Size desiredSize)
Orientation orientation,
double availableCounterSize,
ref double remainingSize,
ref double desiredCounterSize)
ref double desiredCounterSize,
double counterPaddingSize)
{
for (var i = 0; i < _calculatedChildren!.Length; i++)
{
Expand All @@ -222,7 +224,8 @@ private void ApplyMinMaxValues(ref Size desiredSize)
orientation,
fixedSize, // The available size for the child is its defined fixed size
availableCounterSize,
ref desiredCounterSize);
ref desiredCounterSize,
counterPaddingSize);

Decrement(ref remainingSize, fixedSize);
}
Expand All @@ -233,7 +236,8 @@ private void ApplyMinMaxValues(ref Size desiredSize)
Orientation orientation,
double availableCounterSize,
ref double remainingSize,
ref double desiredCounterSize)
ref double desiredCounterSize,
double counterPaddingSize)
{
for (var i = 0; i < _calculatedChildren!.Length; i++)
{
Expand All @@ -249,7 +253,8 @@ private void ApplyMinMaxValues(ref Size desiredSize)
orientation,
double.PositiveInfinity, // We don't want the child to limit its own desired size to available one
availableCounterSize,
ref desiredCounterSize);
ref desiredCounterSize,
counterPaddingSize);

calculatedChild.MeasuredLength = desiredSize;

Expand All @@ -263,7 +268,8 @@ private void ApplyMinMaxValues(ref Size desiredSize)
Orientation orientation,
double availableCounterSize,
ref double remainingSize,
ref double desiredCounterSize)
ref double desiredCounterSize,
double counterPaddingSize)
{
if (double.IsInfinity(remainingSize))
{
Expand Down Expand Up @@ -298,10 +304,10 @@ private void ApplyMinMaxValues(ref Size desiredSize)
continue;
}

MeasureChild(child.Element, orientation, filledSize, availableCounterSize, ref desiredCounterSize);
MeasureChild(child.Element, orientation, filledSize, availableCounterSize, ref desiredCounterSize, counterPaddingSize);

child.MeasuredLength = filledSize;
}
}

return true; // at least one filled child
}
Expand All @@ -311,16 +317,36 @@ private void ApplyMinMaxValues(ref Size desiredSize)
Orientation orientation,
double availableSize,
double availableCounterSize,
ref double desiredCounterSize)
ref double desiredCounterSize,
double counterPaddingSize)
{
var availableSizeForChild = orientation == Orientation.Horizontal
? new Size(availableSize, availableCounterSize)
: new Size(availableCounterSize, availableSize);
var isOrientationHorizontal = orientation is Orientation.Horizontal;
var isPrimaryAlignmentStretch = GetPrimaryAlignment(child) is AutoLayoutPrimaryAlignment.Stretch;
var isCounterAlignmentStretch = GetCounterAlignment(child) is AutoLayoutAlignment.Stretch;

if (child as FrameworkElement is { } frameworkElement)
{
UpdateCounterAlignmentToStretch(ref frameworkElement, isOrientationHorizontal, isPrimaryAlignmentStretch, isCounterAlignmentStretch);

var isStretch = isOrientationHorizontal ?
frameworkElement.VerticalAlignment is VerticalAlignment.Stretch :
frameworkElement.HorizontalAlignment is HorizontalAlignment.Stretch;

isCounterAlignmentStretch = isStretch && (
isOrientationHorizontal ?
double.IsNaN(frameworkElement.Height) && double.IsNaN(GetCounterLength(child))
: double.IsNaN(frameworkElement.Width) && double.IsNaN(GetCounterLength(child))
);
}

var availableSizeForChild = isOrientationHorizontal
? new Size(availableSize, availableCounterSize - (isCounterAlignmentStretch ? counterPaddingSize : 0))
: new Size(availableCounterSize - (isCounterAlignmentStretch ? counterPaddingSize : 0), availableSize);

child.Measure(availableSizeForChild);

double desiredSize;
if (orientation == Orientation.Horizontal)
if (isOrientationHorizontal)
{
desiredSize = child.DesiredSize.Width;
desiredCounterSize = Math.Max(desiredCounterSize, child.DesiredSize.Height);
Expand Down Expand Up @@ -449,4 +475,19 @@ private enum AutoLayoutRole : byte
Filled,
Independent
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void UpdateCounterAlignmentToStretch(ref FrameworkElement frameworkElement, bool isHorizontal, bool isPrimaryAlignmentStretch, bool isCounterAlignmentStretch)
{
if (isHorizontal)
{
frameworkElement.HorizontalAlignment = isPrimaryAlignmentStretch ? HorizontalAlignment.Stretch : frameworkElement.HorizontalAlignment;
frameworkElement.VerticalAlignment = isCounterAlignmentStretch ? VerticalAlignment.Stretch : frameworkElement.VerticalAlignment;
}
else
{
frameworkElement.VerticalAlignment = isPrimaryAlignmentStretch ? VerticalAlignment.Stretch : frameworkElement.VerticalAlignment;
frameworkElement.HorizontalAlignment = isCounterAlignmentStretch ? HorizontalAlignment.Stretch : frameworkElement.HorizontalAlignment;
}
}
}

0 comments on commit fc3ece3

Please sign in to comment.