Skip to content
Open
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 @@ -548,6 +548,59 @@ public void StretchAnchoredControl_WithHealthyNegativeTrailingAnchor_StretchesWi
Assert.Equal(new Rectangle(7, 175, 1511, 217), stretchControl.Bounds);
}

[StaFact]
public void StretchAnchoredControl_WithNegativeTrailingAnchorCapturedAgainstTransientSmallerParent_RefreshesFromSpecifiedBounds()
{
using StretchTestContainer parent = new()
{
Bounds = new Rectangle(0, 0, 1515, 448),
SimulatedDisplayRectangle = new Rectangle(0, 0, 1515, 448)
};
using Panel stretchControl = new()
{
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right,
Bounds = new Rectangle(0, 0, 669, 448)
};
using GroupBox trailingSibling = new()
{
Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right,
Bounds = new Rectangle(1142, 0, 373, 448)
};

parent.Controls.Add(stretchControl);
parent.Controls.Add(trailingSibling);

// TR CargoWise trace shape: the stretch control's V1 anchor metadata was captured while
// the parent was transiently narrower than its design-time display rectangle. Projecting
// that negative trailing anchor into the final wider parent makes the control too wide.
SetSpecifiedBounds(parent, new Rectangle(0, 0, 1039, 448));
SetSpecifiedBounds(stretchControl, new Rectangle(0, 0, 669, 448));
SetSpecifiedBounds(trailingSibling, new Rectangle(679, 0, 373, 448));

DefaultLayout.SetAnchorInfo(
stretchControl,
CreateAnchorInfo(
left: 0,
top: 0,
right: -211,
bottom: 0,
displayRectangle: new Rectangle(0, 0, 880, 448)));

parent.PerformLayout();

DefaultLayout.AnchorInfo refreshedAnchorInfo = DefaultLayout.GetAnchorInfo(stretchControl)!;

Assert.Equal(-370, refreshedAnchorInfo.Right);

parent.PerformLayout();

Assert.Equal(new Rectangle(0, 0, 1145, 448), stretchControl.Bounds);
Assert.True(
stretchControl.Right <= trailingSibling.Left + 3,
$"Stretch control should no longer project to the stale transient width. "
+ $"StretchControl={stretchControl.Bounds}, TrailingSibling={trailingSibling.Bounds}");
}

[StaFact]
public void StretchAnchoredControl_WithStaleSpecifiedSizeAndHealthyAnchors_DoesNotRefreshAnchors()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,12 @@ private static bool ShouldRefreshAnchorInfoForStaleStretchAnchors(
{
useSpecifiedDisplayRectangleForStretchRefresh = false;

if (!ScaleHelper.IsScalingRequirementMet || element.Container is not { } container)
if (element.Container is not { } container)
{
return false;
}

bool isScalingRequirementMet = ScaleHelper.IsScalingRequirementMet;
Rectangle specifiedContainerBounds = CommonProperties.GetSpecifiedBounds(container);
Rectangle specifiedElementBounds = CommonProperties.GetSpecifiedBounds(element);

Expand All @@ -94,13 +95,15 @@ private static bool ShouldRefreshAnchorInfoForStaleStretchAnchors(
specifiedElementBounds.Height);

if (hasDisplayRectangleGrowth
&& IsSpecifiedDisplayRectangleLikelyStale(specifiedDisplayRect, anchorInfo.DisplayRectangle))
&& IsSpecifiedDisplayRectangleLikelyStale(specifiedDisplayRect, anchorInfo.DisplayRectangle)
&& IsSpecifiedDisplayRectangleLikelyStale(specifiedDisplayRect, displayRect))
{
return false;
}

bool hasStaleHorizontalStretchAnchor = IsAnchored(anchor, AnchorStyles.Left)
&& IsAnchored(anchor, AnchorStyles.Right)
&& isScalingRequirementMet
&& anchorInfo.Right < 0
&& hasDisplayRectangleGrowth
&& IsProjectedStretchAnchorSmallerThanExpected(
Expand All @@ -112,6 +115,7 @@ private static bool ShouldRefreshAnchorInfoForStaleStretchAnchors(

bool hasStaleVerticalStretchAnchor = IsAnchored(anchor, AnchorStyles.Top)
&& IsAnchored(anchor, AnchorStyles.Bottom)
&& isScalingRequirementMet
&& anchorInfo.Bottom < 0
&& hasDisplayRectangleGrowth
&& IsProjectedStretchAnchorSmallerThanExpected(
Expand All @@ -121,16 +125,55 @@ private static bool ShouldRefreshAnchorInfoForStaleStretchAnchors(
effectiveSpecifiedHeight,
specifiedDisplayRect.Height);

bool hasOversizedHorizontalStretchAnchor = IsAnchored(anchor, AnchorStyles.Left)
bool hasOversizedHorizontalStretchAnchorWithPositiveTrailingOffset = IsAnchored(anchor, AnchorStyles.Left)
&& IsAnchored(anchor, AnchorStyles.Right)
&& isScalingRequirementMet
&& anchorInfo.Right > 0
&& IsLargerThanExpectedStretchedSize(bounds.Width, specifiedElementBounds.Width, displayRect.Width, specifiedDisplayRect.Width);

bool hasOversizedVerticalStretchAnchor = IsAnchored(anchor, AnchorStyles.Top)
bool hasOversizedVerticalStretchAnchorWithPositiveTrailingOffset = IsAnchored(anchor, AnchorStyles.Top)
&& IsAnchored(anchor, AnchorStyles.Bottom)
&& isScalingRequirementMet
&& anchorInfo.Bottom > 0
&& IsLargerThanExpectedStretchedSize(bounds.Height, specifiedElementBounds.Height, displayRect.Height, specifiedDisplayRect.Height);

bool hasOversizedHorizontalStretchAnchorWithNegativeTrailingOffset = IsAnchored(anchor, AnchorStyles.Left)
&& IsAnchored(anchor, AnchorStyles.Right)
&& anchorInfo.Right < 0
&& hasDisplayRectangleGrowth
&& IsSpecifiedDisplaySizeBetweenOriginalAndCurrent(
specifiedDisplayRect.Width,
anchorInfo.DisplayRectangle.Width,
displayRect.Width)
&& IsProjectedStretchAnchorLargerThanExpected(
displayRect.Width,
anchorInfo.Left,
anchorInfo.Right,
effectiveSpecifiedWidth,
specifiedDisplayRect.Width);

bool hasOversizedVerticalStretchAnchorWithNegativeTrailingOffset = IsAnchored(anchor, AnchorStyles.Top)
&& IsAnchored(anchor, AnchorStyles.Bottom)
&& anchorInfo.Bottom < 0
&& hasDisplayRectangleGrowth
&& IsSpecifiedDisplaySizeBetweenOriginalAndCurrent(
specifiedDisplayRect.Height,
anchorInfo.DisplayRectangle.Height,
displayRect.Height)
&& IsProjectedStretchAnchorLargerThanExpected(
displayRect.Height,
anchorInfo.Top,
anchorInfo.Bottom,
effectiveSpecifiedHeight,
specifiedDisplayRect.Height);

bool hasOversizedHorizontalStretchAnchor =
hasOversizedHorizontalStretchAnchorWithPositiveTrailingOffset
|| hasOversizedHorizontalStretchAnchorWithNegativeTrailingOffset;
bool hasOversizedVerticalStretchAnchor =
hasOversizedVerticalStretchAnchorWithPositiveTrailingOffset
|| hasOversizedVerticalStretchAnchorWithNegativeTrailingOffset;

useSpecifiedDisplayRectangleForStretchRefresh = hasOversizedHorizontalStretchAnchor || hasOversizedVerticalStretchAnchor;

return hasStaleHorizontalStretchAnchor
Expand Down Expand Up @@ -284,6 +327,37 @@ private static bool IsProjectedStretchAnchorSmallerThanExpected(
return IsSmallerThanExpectedStretchedSize(projectedSize, specifiedSize, currentDisplaySize, specifiedDisplaySize);
}

private static bool IsProjectedStretchAnchorLargerThanExpected(
int currentDisplaySize,
int leadingAnchor,
int trailingAnchor,
int specifiedSize,
int specifiedDisplaySize)
{
if (specifiedSize <= 0 || currentDisplaySize <= 0 || specifiedDisplaySize <= 0)
{
return false;
}

int projectedSize = Math.Max(0, currentDisplaySize + trailingAnchor - leadingAnchor);

return IsLargerThanExpectedStretchedSize(projectedSize, specifiedSize, currentDisplaySize, specifiedDisplaySize);
}

private static bool IsSpecifiedDisplaySizeBetweenOriginalAndCurrent(
int specifiedDisplaySize,
int originalDisplaySize,
int currentDisplaySize)
{
if (specifiedDisplaySize <= 0 || originalDisplaySize <= 0 || currentDisplaySize <= 0)
{
return false;
}

return specifiedDisplaySize > originalDisplaySize
&& specifiedDisplaySize < currentDisplaySize;
}

private static int GetEffectiveSpecifiedSizeForStretchRefresh(
int anchorDisplaySize,
int leadingAnchor,
Expand Down
Loading