Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Right padding becomes negative under certain conditions (backport #634) #645

Merged
merged 1 commit into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}
}
Loading