Fixes #4493 - GetViewsUnderLocation does not return subviews of Adornment if Parent has a Subview under Adornment (#4507)

* Initial plan

* Add failing test that reproduces GetViewsUnderLocation bug

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Fix GetViewsUnderLocation to correctly order adornment subviews

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Remove debug output from test

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Address code review: Extract duplicate coordinate conversion

Co-authored-by: tig <585482+tig@users.noreply.github.com>

* Code cleanup

* code cleanup

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
Copilot
2025-12-18 06:31:07 -07:00
committed by GitHub
parent ff18ad4532
commit 993487d0a1
2 changed files with 129 additions and 71 deletions

View File

@@ -1,6 +1,4 @@
#nullable enable
namespace ViewBaseTests.Mouse;
namespace ViewBaseTests.Mouse;
[Trait ("Category", "Input")]
public class GetViewsUnderLocationTests
@@ -145,5 +143,87 @@ public class GetViewsUnderLocationTests
Assert.Equal (expectedAdornmentType, containedType);
}
}
[Fact]
public void GetViewsUnderLocation_Returns_Adornment_Subview_When_Parent_Has_Subview_At_Same_Location ()
{
// Arrange - Reproduces the bug where:
// - Parent has ExpanderButton in its Border
// - A subview with X=-1 (extends outside parent's content) has a Border that overlaps ExpanderButton
// - Bug: GetViewsUnderLocation returns subview.Border instead of ExpanderButton
IApplication app = Application.Create ();
Runnable<bool> runnable = new ()
{
Width = 50,
Height = 50
};
app.Begin (runnable);
// Create parent view
var parent = new View
{
X = 0,
Y = 0,
Width = 30,
Height = 10
};
parent.Border!.Thickness = new (1);
parent.Border.ViewportSettings = ViewportSettingsFlags.None;
// Add ExpanderButton to parent's Border at (0, 0)
// Since parent.Border has thickness=1, the Border's viewport starts at (0,0) screen coords
// And the ExpanderButton at (0,0) relative to Border viewport is at screen (0,0)
var expanderButton = new Button
{
X = 0,
Y = 0,
Width = 1,
Height = 1,
Text = ">",
ShadowStyle = ShadowStyle.None
};
parent.Border.Add (expanderButton);
// Add a subview at X=-1, Y=-1 (extends outside parent's Viewport in both dimensions)
// The subview's Border will overlap with the ExpanderButton location
var childView = new View
{
X = -1, // This causes child's left edge to be at screen X=0 (parent content starts at X=1)
Y = -1, // This causes child's top edge to be at screen Y=0 (parent content starts at Y=1)
Width = 20,
Height = 5
};
childView.Border!.Thickness = new (1);
childView.Border!.ViewportSettings = ViewportSettingsFlags.None;
parent.Add (childView);
runnable.Add (parent);
runnable.Layout ();
// Get screen location of ExpanderButton
Rectangle buttonFrame = expanderButton.FrameToScreen ();
Point testLocation = buttonFrame.Location;
// Verify that childView.Border also contains this location (this is the bug scenario)
Rectangle childBorderFrame = childView.Border.FrameToScreen ();
Assert.True (
childBorderFrame.Contains (testLocation),
$"Test setup failed: childView.Border ({childBorderFrame}) should contain testLocation ({testLocation})");
// Act
List<View?> viewsUnderLocation = runnable.GetViewsUnderLocation (testLocation, ViewportSettingsFlags.None);
// Assert
View? deepestView = viewsUnderLocation.LastOrDefault ();
Assert.NotNull (deepestView);
// The ExpanderButton is a subview of parent.Border, which is processed before childView
// But childView.Border is processed AFTER ExpanderButton, causing the bug
// The correct deepest view should be ExpanderButton, not childView.Border
Assert.Equal (expanderButton, deepestView);
app.Dispose ();
}
}