Skip to content

Commit

Permalink
Merge pull request #18361 from unoplatform/mergify/bp/release/stable/…
Browse files Browse the repository at this point in the history
…5.4/pr-18336

fix: Port "non-clipping subtree" logic from WinUI (backport #18336)
  • Loading branch information
jeromelaban authored Oct 4, 2024
2 parents 06f6c00 + 92cb662 commit 56fbc19
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 5 deletions.
31 changes: 31 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,37 @@ private bool WantsScrollViewerToObscureAvailableSizeBasedOnScrollBarVisibility(O
return (spPanel as FrameworkElement)?.WantsScrollViewerToObscureAvailableSizeBasedOnScrollBarVisibility(orientation) ?? true;
}

// Itemspresenter is the lynchpin in deciding whether we want to be in a non clipping subtree.
// Basically, when he decided to not want infinity, even though we were in a scrolling configuration,
// we want the measures underneath it to not constrain the desiredsize to the availablesize. That will allow
// wrapping uielements (like textblock) to size correctly, and still allow containers that want to be bigger
// to look good.
// Itemspresenter will set the value on himself (used during layout) and on the panel. Listview will set it on the
// items (so that individual measure on them will work).
internal bool EvaluateAndSetNonClippingBehavior(bool isNotBeingPassedInfinity)
{
bool result = false;
if (Panel is ItemsStackPanel panel)
{
// we only want the behavior in an isp at the moment

// first set it to ourselves
IsNonClippingSubtree = isNotBeingPassedInfinity;

// in the case of a modernpanel, lets have this itemspresenter not clip to the available size
// in overconstrained scenarios
// we're just passing through the setting to the panel here in an effort to make itemspresenter behave like a
// 'dumb' passthrough. The real logic was performed when measuring the scrollcontentpresenter

// we pass it along - the reason we want these individual elements also to have the correct value is because
// they could potentially be measured independently
panel.IsNonClippingSubtree = isNotBeingPassedInfinity;

result = isNotBeingPassedInfinity;
}

return result;
}

protected override Size ArrangeOverride(Size finalSize)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,24 +186,32 @@ protected override Size MeasureOverride(Size availableSize)
}
}

// when set to true, this means that we wanted to set to infinity but were blocked in doing it.
bool childPreventsInfiniteAvailableWidth = false;
bool childPreventsInfiniteAvailableHeight = false;

if (CanVerticallyScroll)
{
var childPreventsInfiniteAvailableHeight = !child.WantsScrollViewerToObscureAvailableSizeBasedOnScrollBarVisibility(Orientation.Vertical);
childPreventsInfiniteAvailableHeight = !child.WantsScrollViewerToObscureAvailableSizeBasedOnScrollBarVisibility(Orientation.Vertical);
if (!sizesContentToTemplatedParent && !childPreventsInfiniteAvailableHeight)
{
slotSize.Height = double.PositiveInfinity;
}
}
if (CanHorizontallyScroll)
{
var childPreventsInfiniteAvailableWidth = !child.WantsScrollViewerToObscureAvailableSizeBasedOnScrollBarVisibility(Orientation.Horizontal);
childPreventsInfiniteAvailableWidth = !child.WantsScrollViewerToObscureAvailableSizeBasedOnScrollBarVisibility(Orientation.Horizontal);
if (!sizesContentToTemplatedParent && !childPreventsInfiniteAvailableWidth)
{
slotSize.Width = double.PositiveInfinity;
}
}

if (child is ItemsPresenter itemsPresenter)
{
itemsPresenter.EvaluateAndSetNonClippingBehavior(childPreventsInfiniteAvailableWidth || childPreventsInfiniteAvailableHeight);
}

child.Measure(slotSize);

var desired = child.DesiredSize;
Expand Down
4 changes: 1 addition & 3 deletions src/Uno.UI/UI/Xaml/FrameworkElement.Layout.crossruntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -309,9 +309,7 @@ private void InnerMeasureCore(Size availableSize)

// only clip and constrain if the tree wants that.
// currently only listviewitems do not want clipping
// UNO TODO

//if (!pLayoutManager->GetIsInNonClippingTree())
if (!IsInNonClippingTree)
{
// In overconstrained scenario, parent wins and measured size of the child,
// including any sizes set or computed, can not be larger then
Expand Down
11 changes: 11 additions & 0 deletions src/Uno.UI/UI/Xaml/UIElement.Layout.crossruntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public partial class UIElement : DependencyObject
/// </summary>
internal bool ShouldInterceptInvalidate { get; set; }

// In WinUI, this is in LayoutManager. For Uno, we make it static in FE for now.
private protected static bool IsInNonClippingTree { get; set; }

public void InvalidateMeasure()
{
if (ShouldInterceptInvalidate || IsMeasureDirty || IsLayoutFlagSet(LayoutFlag.MeasuringSelf))
Expand Down Expand Up @@ -213,6 +216,12 @@ private void DoMeasure(Size availableSize)

var remainingTries = MaxLayoutIterations;

// remember whether we need to set this value back
var wasInNonClippingTree = IsInNonClippingTree;
// once entering a tree that is non-clipping, we don't get out of it
// remember this for down-stream
IsInNonClippingTree = IsNonClippingSubtree || wasInNonClippingTree;

while (--remainingTries > 0)
{
if (isDirty)
Expand Down Expand Up @@ -306,6 +315,8 @@ private void DoMeasure(Size availableSize)

break;
}

IsInNonClippingTree = wasInNonClippingTree;
}

internal virtual void MeasureCore(Size availableSize)
Expand Down
2 changes: 2 additions & 0 deletions src/Uno.UI/UI/Xaml/UIElement.mux.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1933,5 +1933,7 @@ internal virtual void LeaveImpl(LeaveParams @params)

internal virtual bool WantsScrollViewerToObscureAvailableSizeBasedOnScrollBarVisibility(Orientation horizontal)
=> true;

internal bool IsNonClippingSubtree { get; set; }
}
}

0 comments on commit 56fbc19

Please sign in to comment.