diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs
index 2eff63efb..670b5674e 100644
--- a/Terminal.Gui/Application.cs
+++ b/Terminal.Gui/Application.cs
@@ -1374,7 +1374,8 @@ public static partial class Application
return;
}
- var view = View.FindDeepestView (Current, a.MouseEvent.X, a.MouseEvent.Y, out int screenX, out int screenY);
+ // TODO: In PR #3273, FindDeepestView will return adornments. Update logic below to fix adornment mouse handling
+ var view = View.FindDeepestView (Current, a.MouseEvent.X, a.MouseEvent.Y);
if (view is { WantContinuousButtonPressed: true })
{
@@ -1437,7 +1438,7 @@ public static partial class Application
&& a.MouseEvent.Flags != 0)
{
View? top = FindDeepestTop (Top, a.MouseEvent.X, a.MouseEvent.Y);
- view = View.FindDeepestView (top, a.MouseEvent.X, a.MouseEvent.Y, out screenX, out screenY);
+ view = View.FindDeepestView (top, a.MouseEvent.X, a.MouseEvent.Y);
if (view is { } && view != OverlappedTop && top != Current)
{
@@ -1450,6 +1451,8 @@ public static partial class Application
return;
}
+ var screen = view.FrameToScreen ();
+
// Work inside-out (Padding, Border, Margin)
// TODO: Debate whether inside-out or outside-in is the right strategy
if (AdornmentHandledMouseEvent (view.Padding, a))
@@ -1469,11 +1472,11 @@ public static partial class Application
var me = new MouseEvent
{
- X = screenX,
- Y = screenY,
+ X = a.MouseEvent.X - screen.X,
+ Y = a.MouseEvent.Y - screen.Y,
Flags = a.MouseEvent.Flags,
- OfX = screenX,
- OfY = screenY,
+ OfX = a.MouseEvent.X - screen.X,
+ OfY = a.MouseEvent.Y - screen.Y,
View = view
};
diff --git a/Terminal.Gui/Input/Responder.cs b/Terminal.Gui/Input/Responder.cs
index 9f38757fa..d7f2ce6c3 100644
--- a/Terminal.Gui/Input/Responder.cs
+++ b/Terminal.Gui/Input/Responder.cs
@@ -57,6 +57,9 @@ public class Responder : IDisposable
public event EventHandler Disposing;
/// Method invoked when a mouse event is generated
+ ///
+ /// The coordinates are relative to .
+ ///
/// true, if the event was handled, false otherwise.
/// Contains the details about the mouse event.
public virtual bool MouseEvent (MouseEvent mouseEvent) { return false; }
@@ -81,6 +84,9 @@ public class Responder : IDisposable
/// Called when the mouse first enters the view; the view will now receives mouse events until the mouse leaves
/// the view. At which time, will be called.
///
+ ///
+ /// The coordinates are relative to .
+ ///
///
/// true, if the event was handled, false otherwise.
public virtual bool OnMouseEnter (MouseEvent mouseEvent) { return false; }
@@ -89,6 +95,9 @@ public class Responder : IDisposable
/// Called when the mouse has moved outside of the view; the view will no longer receive mouse events (until the
/// mouse moves within the view again and is called).
///
+ ///
+ /// The coordinates are relative to .
+ ///
///
/// true, if the event was handled, false otherwise.
public virtual bool OnMouseLeave (MouseEvent mouseEvent) { return false; }
diff --git a/Terminal.Gui/View/Adornment/Adornment.cs b/Terminal.Gui/View/Adornment/Adornment.cs
index a88186d92..4f47e6e02 100644
--- a/Terminal.Gui/View/Adornment/Adornment.cs
+++ b/Terminal.Gui/View/Adornment/Adornment.cs
@@ -33,7 +33,7 @@ public class Adornment : View
/// Gets the rectangle that describes the inner area of the Adornment. The Location is always (0,0).
public override Rectangle Bounds
{
- get => Thickness?.GetInside (new (Point.Empty, Frame.Size)) ?? new Rectangle (Point.Empty, Frame.Size);
+ get => new Rectangle (Point.Empty, Thickness?.GetInside (new (Point.Empty, Frame.Size)).Size ?? Frame.Size);
// QUESTION: So why even have a setter then?
set => throw new InvalidOperationException ("It makes no sense to set Bounds of a Thickness.");
}
@@ -100,17 +100,19 @@ public class Adornment : View
///
public override Rectangle FrameToScreen ()
{
+ if (Parent is null)
+ {
+ return Frame;
+ }
+
// Adornments are *Children* of a View, not SubViews. Thus View.FrameToScreen will not work.
// To get the screen-relative coordinates of a Adornment, we need to know who
// the Parent is
- Rectangle ret = Parent?.Frame ?? Frame;
- ret.Size = Frame.Size;
-
- ret.Location = Parent?.FrameToScreen ().Location ?? ret.Location;
+ Rectangle parent = Parent.FrameToScreen ();
// We now have coordinates relative to our View. If our View's SuperView has
// a SuperView, keep going...
- return ret;
+ return new (new (parent.X + Frame.X, parent.Y + Frame.Y), Frame.Size);
}
/// Does nothing for Adornment
diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs
index 3fe411799..85441c1e5 100644
--- a/Terminal.Gui/View/Layout/ViewLayout.cs
+++ b/Terminal.Gui/View/Layout/ViewLayout.cs
@@ -545,28 +545,49 @@ public partial class View
}
}
- #nullable enable
+#nullable enable
/// Finds which view that belong to the superview at the provided location.
/// The superview where to look for.
/// The column location in the superview.
/// The row location in the superview.
- /// The found view screen relative column location.
- /// The found view screen relative row location.
+ /// TODO: Remove this in PR #3273
///
/// The view that was found at the and coordinates.
/// if no view was found.
///
+
// CONCURRENCY: This method is not thread-safe.
// Undefined behavior and likely program crashes are exposed by unsynchronized access to InternalSubviews.
- public static View? FindDeepestView (View? start, int x, int y, out int resultX, out int resultY)
+ public static View? FindDeepestView (View? start, int x, int y, bool findAdornments = false)
{
- resultY = resultX = 0;
-
- if (start is null || !start.Frame.Contains (x, y))
+ if (start is null || !start.Visible)
{
return null;
}
+ if (!start.Frame.Contains (x, y))
+ {
+ return null;
+ }
+
+ if (findAdornments)
+ {
+ // TODO: This is a temporary hack for PR #3273; it is not actually used anywhere but unit tests at this point.
+ if (start.Margin.Thickness.Contains (start.Margin.Frame, x, y))
+ {
+ return start.Margin;
+ }
+ if (start.Border.Thickness.Contains (start.Border.Frame, x, y))
+ {
+ return start.Border;
+ }
+ if (start.Padding.Thickness.Contains (start.Padding.Frame, x, y))
+ {
+ return start.Padding;
+ }
+
+ }
+
if (start.InternalSubviews is { Count: > 0 })
{
Point boundsOffset = start.GetBoundsOffset ();
@@ -579,19 +600,14 @@ public partial class View
if (v.Visible && v.Frame.Contains (rx, ry))
{
- View? deep = FindDeepestView (v, rx, ry, out resultX, out resultY);
-
+ View? deep = FindDeepestView (v, rx, ry, findAdornments);
return deep ?? v;
}
}
}
-
- resultX = x - start.Frame.X;
- resultY = y - start.Frame.Y;
-
return start;
}
- #nullable restore
+#nullable restore
/// Gets the with a screen-relative location.
/// The location and size of the view in screen-relative coordinates.
diff --git a/Terminal.Gui/Views/Menu/Menu.cs b/Terminal.Gui/Views/Menu/Menu.cs
index 28f9b1823..37de2476b 100644
--- a/Terminal.Gui/Views/Menu/Menu.cs
+++ b/Terminal.Gui/Views/Menu/Menu.cs
@@ -727,13 +727,7 @@ internal sealed class Menu : View
locationOffset.Y += SuperView.Border.Thickness.Top;
}
- View view = FindDeepestView (
- this,
- a.MouseEvent.X + locationOffset.X,
- a.MouseEvent.Y + locationOffset.Y,
- out int rx,
- out int ry
- );
+ View view = FindDeepestView (this, a.MouseEvent.X + locationOffset.X, a.MouseEvent.Y + locationOffset.Y);
if (view == this)
{
@@ -742,7 +736,13 @@ internal sealed class Menu : View
throw new InvalidOperationException ("This shouldn't running on a invisible menu!");
}
- var nme = new MouseEvent { X = rx, Y = ry, Flags = a.MouseEvent.Flags, View = view };
+ var screen = view.FrameToScreen ();
+ var nme = new MouseEvent {
+ X = a.MouseEvent.X - screen.X,
+ Y = a.MouseEvent.Y - screen.Y,
+ Flags = a.MouseEvent.Flags,
+ View = view
+ };
if (MouseEvent (nme) || a.MouseEvent.Flags == MouseFlags.Button1Pressed || a.MouseEvent.Flags == MouseFlags.Button1Released)
{
diff --git a/UnitTests/View/Adornment/AdornmentTests.cs b/UnitTests/View/Adornment/AdornmentTests.cs
index 8cc054e8b..6b2d5765b 100644
--- a/UnitTests/View/Adornment/AdornmentTests.cs
+++ b/UnitTests/View/Adornment/AdornmentTests.cs
@@ -7,6 +7,46 @@ public class AdornmentTests
private readonly ITestOutputHelper _output;
public AdornmentTests (ITestOutputHelper output) { _output = output; }
+ [Fact]
+ public void Bounds_Location_Always_Empty_Size_Correct ()
+ {
+ var view = new View
+ {
+ X = 1,
+ Y = 2,
+ Width = 20,
+ Height = 31
+ };
+
+ var marginThickness = 1;
+ view.Margin.Thickness = new Thickness (marginThickness);
+
+ var borderThickness = 2;
+ view.Border.Thickness = new Thickness (borderThickness);
+
+ var paddingThickness = 3;
+ view.Padding.Thickness = new Thickness (paddingThickness);
+
+ view.BeginInit ();
+ view.EndInit ();
+
+ Assert.Equal (new Rectangle (1, 2, 20, 31), view.Frame);
+ Assert.Equal (new Rectangle (0, 0, 8, 19), view.Bounds);
+
+ Assert.Equal (new Rectangle (0, 0, view.Margin.Frame.Width - marginThickness * 2, view.Margin.Frame.Height - marginThickness * 2), view.Margin.Bounds);
+
+ Assert.Equal (new Rectangle (0, 0, view.Border.Frame.Width - borderThickness * 2, view.Border.Frame.Height - borderThickness * 2), view.Border.Bounds);
+
+ Assert.Equal (
+ new Rectangle (
+ 0,
+ 0,
+ view.Padding.Frame.Width - (marginThickness + borderThickness) * 2,
+ view.Padding.Frame.Height - (marginThickness + borderThickness) * 2),
+ view.Padding.Bounds);
+ }
+
+ // Test that Adornment.Bounds_get override uses Parent not SuperView
[Fact]
public void BoundsToScreen_Uses_Parent_Not_SuperView ()
{
@@ -25,6 +65,134 @@ public class AdornmentTests
Assert.Equal (new Rectangle (2, 4, 5, 5), boundsAsScreen);
}
+ [Fact]
+ public void Frames_are_Parent_SuperView_Relative ()
+ {
+ var view = new View
+ {
+ X = 1,
+ Y = 2,
+ Width = 20,
+ Height = 31
+ };
+
+ var marginThickness = 1;
+ view.Margin.Thickness = new Thickness (marginThickness);
+
+ var borderThickness = 2;
+ view.Border.Thickness = new Thickness (borderThickness);
+
+ var paddingThickness = 3;
+ view.Padding.Thickness = new Thickness (paddingThickness);
+
+ view.BeginInit ();
+ view.EndInit ();
+
+ Assert.Equal (new Rectangle (1, 2, 20, 31), view.Frame);
+ Assert.Equal (new Rectangle (0, 0, 8, 19), view.Bounds);
+
+ // Margin.Frame is always the same as the view frame
+ Assert.Equal (new Rectangle (0, 0, 20, 31), view.Margin.Frame);
+
+ // Border.Frame is View.Frame minus the Margin thickness
+ Assert.Equal (
+ new Rectangle (marginThickness, marginThickness, view.Frame.Width - marginThickness * 2, view.Frame.Height - marginThickness * 2),
+ view.Border.Frame);
+
+ // Padding.Frame is View.Frame minus the Border thickness plus Margin thickness
+ Assert.Equal (
+ new Rectangle (
+ marginThickness + borderThickness,
+ marginThickness + borderThickness,
+ view.Frame.Width - (marginThickness + borderThickness) * 2,
+ view.Frame.Height - (marginThickness + borderThickness) * 2),
+ view.Padding.Frame);
+ }
+
+ // Test that Adornment.FrameToScreen override retains Frame.Size
+ [Theory]
+ [InlineData (0, 0, 0)]
+ [InlineData (0, 1, 1)]
+ [InlineData (0, 10, 10)]
+ [InlineData (1, 0, 0)]
+ [InlineData (1, 1, 1)]
+ [InlineData (1, 10, 10)]
+ public void FrameToScreen_Retains_Frame_Size (int marginThickness, int w, int h)
+ {
+ var parent = new View { X = 1, Y = 2, Width = w, Height = h };
+ parent.Margin.Thickness = new Thickness (marginThickness);
+
+ parent.BeginInit ();
+ parent.EndInit ();
+
+ Assert.Equal (new Rectangle (1, 2, w, h), parent.Frame);
+ Assert.Equal (new Rectangle (0, 0, w, h), parent.Margin.Frame);
+
+ Assert.Equal (parent.Frame, parent.Margin.FrameToScreen ());
+ }
+
+ // Test that Adornment.FrameToScreen override returns Frame if Parent is null
+ [Fact]
+ public void FrameToScreen_Returns_Frame_If_Parent_Is_Null ()
+ {
+ var a = new Adornment
+ {
+ X = 1,
+ Y = 2,
+ Width = 3,
+ Height = 4
+ };
+
+ Assert.Null (a.Parent);
+ Assert.Equal (a.Frame, a.FrameToScreen ());
+ }
+
+ // Test that Adornment.FrameToScreen override returns correct location
+ [Theory]
+ [InlineData (0, 0, 0, 0)]
+ [InlineData (0, 0, 1, 1)]
+ [InlineData (0, 0, 10, 10)]
+ [InlineData (1, 0, 0, 0)]
+ [InlineData (1, 0, 1, 1)]
+ [InlineData (1, 0, 10, 10)]
+ [InlineData (0, 1, 0, 0)]
+ [InlineData (0, 1, 1, 1)]
+ [InlineData (0, 1, 10, 10)]
+ [InlineData (1, 1, 0, 0)]
+ [InlineData (1, 1, 1, 1)]
+ [InlineData (1, 1, 10, 10)]
+ public void FrameToScreen_Returns_Screen_Location (int marginThickness, int borderThickness, int x, int y)
+ {
+ var superView = new View
+ {
+ X = 1,
+ Y = 1,
+ Width = 20,
+ Height = 20
+ };
+ superView.Margin.Thickness = new Thickness (marginThickness);
+ superView.Border.Thickness = new Thickness (borderThickness);
+
+ var view = new View { X = x, Y = y, Width = 1, Height = 1 };
+ superView.Add (view);
+ superView.BeginInit ();
+ superView.EndInit ();
+
+ Assert.Equal (new Rectangle (x, y, 1, 1), view.Frame);
+ Assert.Equal (new Rectangle (0, 0, 20, 20), superView.Margin.Frame);
+
+ Assert.Equal (
+ new Rectangle (marginThickness, marginThickness, 20 - marginThickness * 2, 20 - marginThickness * 2),
+ superView.Border.Frame
+ );
+
+ Assert.Equal (
+ new Rectangle (superView.Frame.X + marginThickness, superView.Frame.Y + marginThickness, 20 - marginThickness * 2, 20 - marginThickness * 2),
+ superView.Border.FrameToScreen ()
+ );
+ }
+
+ // Test that Adornment.FrameToScreen override uses Parent not SuperView
[Fact]
public void FrameToScreen_Uses_Parent_Not_SuperView ()
{
diff --git a/UnitTests/View/FindDeepestViewTests.cs b/UnitTests/View/FindDeepestViewTests.cs
new file mode 100644
index 000000000..6434eaa8c
--- /dev/null
+++ b/UnitTests/View/FindDeepestViewTests.cs
@@ -0,0 +1,285 @@
+using UICatalog.Scenarios;
+using Xunit.Abstractions;
+
+namespace Terminal.Gui.ViewTests;
+
+///
+/// Tests View.FindDeepestView
+///
+///
+public class FindDeepestViewTests (ITestOutputHelper output)
+{
+ // Test that FindDeepestView returns the correct view if the start view has no subviews
+ [Theory]
+ [InlineData (0, 0)]
+ [InlineData (1, 1)]
+ [InlineData (2, 2)]
+ public void Returns_Start_If_No_SubViews (int testX, int testY)
+ {
+ var start = new View ()
+ {
+ Width = 10, Height = 10,
+ };
+
+ Assert.Same (start, View.FindDeepestView (start, testX, testY));
+ }
+
+ // Test that FindDeepestView returns null if the start view has no subviews and coords are outside the view
+ [Theory]
+ [InlineData (0, 0)]
+ [InlineData (2, 1)]
+ [InlineData (20, 20)]
+ public void Returns_Null_If_No_SubViews_Coords_Outside (int testX, int testY)
+ {
+ var start = new View ()
+ {
+ X = 1, Y = 2,
+ Width = 10, Height = 10,
+ };
+
+ Assert.Null(View.FindDeepestView (start, testX, testY));
+ }
+
+ [Theory]
+ [InlineData (0, 0)]
+ [InlineData (2, 1)]
+ [InlineData (20, 20)]
+ public void Returns_Null_If_Start_Not_Visible (int testX, int testY)
+ {
+ var start = new View ()
+ {
+ X = 1, Y = 2,
+ Width = 10, Height = 10,
+ Visible = false,
+ };
+
+ Assert.Null (View.FindDeepestView (start, testX, testY));
+ }
+
+ // Test that FindDeepestView returns the correct view if the start view has subviews
+ [Theory]
+ [InlineData (0, 0, false)]
+ [InlineData (1, 1, false)]
+ [InlineData (9, 9, false)]
+ [InlineData (10, 10, false)]
+ [InlineData (6, 7, false)]
+
+ [InlineData (1, 2, true)]
+ [InlineData (5, 6, true)]
+ public void Returns_Correct_If_SubViews (int testX, int testY, bool expectedSubViewFound)
+ {
+ var start = new View ()
+ {
+ Width = 10, Height = 10,
+ };
+
+ var subview = new View ()
+ {
+ X = 1, Y = 2,
+ Width = 5, Height = 5,
+ };
+ start.Add (subview);
+
+ var found = View.FindDeepestView (start, testX, testY);
+
+ Assert.Equal (expectedSubViewFound, found == subview);
+ }
+
+ [Theory]
+ [InlineData (0, 0, false)]
+ [InlineData (1, 1, false)]
+ [InlineData (9, 9, false)]
+ [InlineData (10, 10, false)]
+ [InlineData (6, 7, false)]
+ [InlineData (1, 2, false)]
+ [InlineData (5, 6, false)]
+ public void Returns_Null_If_SubView_NotVisible (int testX, int testY, bool expectedSubViewFound)
+ {
+ var start = new View ()
+ {
+ Width = 10, Height = 10,
+ };
+
+ var subview = new View ()
+ {
+ X = 1, Y = 2,
+ Width = 5, Height = 5,
+ Visible = false
+ };
+ start.Add (subview);
+
+ var found = View.FindDeepestView (start, testX, testY);
+
+ Assert.Equal (expectedSubViewFound, found == subview);
+ }
+
+
+ [Theory]
+ [InlineData (0, 0, false)]
+ [InlineData (1, 1, false)]
+ [InlineData (9, 9, false)]
+ [InlineData (10, 10, false)]
+ [InlineData (6, 7, false)]
+ [InlineData (1, 2, false)]
+ [InlineData (5, 6, false)]
+ public void Returns_Null_If_Not_Visible_And_SubView_Visible (int testX, int testY, bool expectedSubViewFound)
+ {
+ var start = new View ()
+ {
+ Width = 10, Height = 10,
+ Visible = false
+ };
+
+ var subview = new View ()
+ {
+ X = 1, Y = 2,
+ Width = 5, Height = 5,
+ };
+ start.Add (subview);
+ subview.Visible = true;
+ Assert.True (subview.Visible);
+ Assert.False (start.Visible);
+ var found = View.FindDeepestView (start, testX, testY);
+
+ Assert.Equal (expectedSubViewFound, found == subview);
+ }
+
+ // Test that FindDeepestView works if the start view has positive Adornments
+ [Theory]
+ [InlineData (0, 0, false)]
+ [InlineData (1, 1, false)]
+ [InlineData (9, 9, false)]
+ [InlineData (10, 10, false)]
+ [InlineData (7, 8, false)]
+ [InlineData (1, 2, false)]
+
+ [InlineData (2, 3, true)]
+ [InlineData (5, 6, true)]
+ [InlineData (2, 3, true)]
+ [InlineData (6, 7, true)]
+ public void Returns_Correct_If_Start_Has_Adornments (int testX, int testY, bool expectedSubViewFound)
+ {
+ var start = new View ()
+ {
+ Width = 10, Height = 10,
+ };
+ start.Margin.Thickness = new Thickness (1);
+
+ var subview = new View ()
+ {
+ X = 1, Y = 2,
+ Width = 5, Height = 5,
+ };
+ start.Add (subview);
+
+ var found = View.FindDeepestView (start, testX, testY, true);
+
+ Assert.Equal (expectedSubViewFound, found == subview);
+ }
+
+ [Theory]
+ [InlineData (0, 0, typeof(Margin))]
+ [InlineData (9, 9, typeof (Margin))]
+
+ [InlineData (1, 1, typeof (Border))]
+ [InlineData (8, 8, typeof (Border))]
+
+ [InlineData (2, 2, typeof (Padding))]
+ [InlineData (7, 7, typeof (Padding))]
+
+ [InlineData (5, 5, typeof (View))]
+ public void Returns_Adornment_If_Start_Has_Adornments (int testX, int testY, Type expectedAdornmentType)
+ {
+ var start = new View ()
+ {
+ Width = 10, Height = 10,
+ };
+ start.Margin.Thickness = new Thickness (1);
+ start.Border.Thickness = new Thickness (1);
+ start.Padding.Thickness = new Thickness (1);
+
+ var subview = new View ()
+ {
+ X = 1, Y = 1,
+ Width = 1, Height = 1,
+ };
+ start.Add (subview);
+
+ var found = View.FindDeepestView (start, testX, testY, true);
+ Assert.Equal(expectedAdornmentType, found.GetType());
+ }
+
+ // Test that FindDeepestView works if the subview has positive Adornments
+ [Theory]
+ [InlineData (0, 0, false)]
+ [InlineData (1, 1, false)]
+ [InlineData (9, 9, false)]
+ [InlineData (10, 10, false)]
+ [InlineData (7, 8, false)]
+ [InlineData (6, 7, false)]
+
+ [InlineData (1, 2, true)]
+ [InlineData (2, 3, true)]
+ [InlineData (5, 6, true)]
+ [InlineData (2, 3, true)]
+ public void Returns_Correct_If_SubView_Has_Adornments (int testX, int testY, bool expectedSubViewFound)
+ {
+ var start = new View ()
+ {
+ Width = 10, Height = 10,
+ };
+
+ var subview = new View ()
+ {
+ X = 1, Y = 2,
+ Width = 5, Height = 5,
+ };
+ subview.Margin.Thickness = new Thickness (1);
+ start.Add (subview);
+
+ var found = View.FindDeepestView (start, testX, testY);
+
+ Assert.Equal (expectedSubViewFound, found == subview);
+ }
+
+ // Test that FindDeepestView works with nested subviews
+ [Theory]
+ [InlineData (0, 0, -1)]
+ [InlineData (9, 9, -1)]
+ [InlineData (10, 10, -1)]
+
+ [InlineData (1, 1, 0)]
+ [InlineData (1, 2, 0)]
+ [InlineData (2, 2, 1)]
+ [InlineData (3, 3, 2)]
+ [InlineData (5, 5, 2)]
+ public void Returns_Correct_With_NestedSubViews (int testX, int testY, int expectedSubViewFound)
+ {
+ var start = new View ()
+ {
+ Width = 10, Height = 10
+ };
+
+ int numSubViews = 3;
+ List subviews = new List ();
+ for (int i = 0; i < numSubViews; i++)
+ {
+ var subview = new View ()
+ {
+ X = 1, Y = 1,
+ Width = 5, Height = 5,
+ };
+ subviews.Add (subview);
+
+ if (i > 0)
+ {
+ subviews [i - 1].Add (subview);
+ }
+ }
+
+ start.Add (subviews [0]);
+
+ var found = View.FindDeepestView (start, testX, testY);
+ Assert.Equal (expectedSubViewFound, subviews.IndexOf(found));
+ }
+}
diff --git a/UnitTests/View/Layout/LayoutTests.cs b/UnitTests/View/Layout/LayoutTests.cs
index b489464ac..ae30919fe 100644
--- a/UnitTests/View/Layout/LayoutTests.cs
+++ b/UnitTests/View/Layout/LayoutTests.cs
@@ -1,4 +1,5 @@
using Xunit.Abstractions;
+using static Unix.Terminal.Curses;
// Alias Console to MockConsole so we don't accidentally use Console
@@ -549,7 +550,7 @@ public class LayoutTests
Assert.Equal (new Rectangle (0, 2, 10, 3), win2.Frame);
Assert.Equal (new Rectangle (0, 0, 8, 1), view2.Frame);
Assert.Equal (new Rectangle (0, 0, 7, 1), view3.Frame);
- var foundView = View.FindDeepestView (top, 9, 4, out int rx, out int ry);
+ var foundView = View.FindDeepestView (top, 9, 4);
Assert.Equal (foundView, view2);
Application.OnMouseEvent (
diff --git a/UnitTests/View/NavigationTests.cs b/UnitTests/View/NavigationTests.cs
index a7b087b22..ac93b2b15 100644
--- a/UnitTests/View/NavigationTests.cs
+++ b/UnitTests/View/NavigationTests.cs
@@ -856,39 +856,46 @@ public class NavigationTests
top.BoundsToScreen (-1, -1, out col, out row);
Assert.Equal (0, col);
Assert.Equal (0, row);
- Assert.Equal (top, View.FindDeepestView (top, 0, 0, out int rx, out int ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
+ var found = View.FindDeepestView (top, 0, 0);
+ Assert.Equal (top, found);
+
+ Assert.Equal (0, found.Frame.X);
+ Assert.Equal (0, found.Frame.Y);
Assert.Equal (new Point (3, 2), top.ScreenToFrame (3, 2));
top.BoundsToScreen (3, 2, out col, out row);
Assert.Equal (4, col);
Assert.Equal (3, row);
- Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
- Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry));
- Assert.Equal (3, rx);
- Assert.Equal (2, ry);
+ found = View.FindDeepestView (top, col, row);
+ Assert.Equal (view, found);
+ //Assert.Equal (0, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
+ found = View.FindDeepestView (top, 3, 2);
+ Assert.Equal (top, found);
+ //Assert.Equal (3, found.FrameToScreen ().X);
+ //Assert.Equal (2, found.FrameToScreen ().Y);
Assert.Equal (new Point (13, 2), top.ScreenToFrame (13, 2));
top.BoundsToScreen (12, 2, out col, out row);
Assert.Equal (13, col);
Assert.Equal (3, row);
- Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry));
- Assert.Equal (9, rx);
- Assert.Equal (0, ry);
+ found = View.FindDeepestView (top, col, row);
+ Assert.Equal (view, found);
+ //Assert.Equal (9, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
top.BoundsToScreen (13, 2, out col, out row);
Assert.Equal (14, col);
Assert.Equal (3, row);
- Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry));
- Assert.Equal (13, rx);
- Assert.Equal (2, ry);
+ found = View.FindDeepestView (top, 13, 2);
+ Assert.Equal (top, found);
+ //Assert.Equal (13, found.FrameToScreen ().X);
+ //Assert.Equal (2, found.FrameToScreen ().Y);
Assert.Equal (new Point (14, 3), top.ScreenToFrame (14, 3));
top.BoundsToScreen (14, 3, out col, out row);
Assert.Equal (15, col);
Assert.Equal (4, row);
- Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
- Assert.Equal (14, rx);
- Assert.Equal (3, ry);
+ found = View.FindDeepestView (top, 14, 3);
+ Assert.Equal (top, found);
+ //Assert.Equal (14, found.FrameToScreen ().X);
+ //Assert.Equal (3, found.FrameToScreen ().Y);
// view
Assert.Equal (new Point (-4, -3), view.ScreenToFrame (0, 0));
@@ -907,30 +914,34 @@ public class NavigationTests
view.BoundsToScreen (-4, -3, out col, out row);
Assert.Equal (0, col);
Assert.Equal (0, row);
- Assert.Equal (top, View.FindDeepestView (top, 0, 0, out rx, out ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
+ found = View.FindDeepestView (top, 0, 0);
+ Assert.Equal (top, found);
+ //Assert.Equal (0, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
Assert.Equal (new Point (-1, -1), view.ScreenToFrame (3, 2));
view.BoundsToScreen (0, 0, out col, out row);
Assert.Equal (4, col);
Assert.Equal (3, row);
- Assert.Equal (view, View.FindDeepestView (top, 4, 3, out rx, out ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
+ found = View.FindDeepestView (top, 4, 3);
+ Assert.Equal (view, found);
+ //Assert.Equal (0, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
Assert.Equal (new Point (9, -1), view.ScreenToFrame (13, 2));
view.BoundsToScreen (10, 0, out col, out row);
Assert.Equal (14, col);
Assert.Equal (3, row);
- Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
- Assert.Equal (14, rx);
- Assert.Equal (3, ry);
+ found = View.FindDeepestView (top, 14, 3);
+ Assert.Equal (top, found);
+ //Assert.Equal (14, found.FrameToScreen ().X);
+ //Assert.Equal (3, found.FrameToScreen ().Y);
Assert.Equal (new Point (10, 0), view.ScreenToFrame (14, 3));
view.BoundsToScreen (11, 1, out col, out row);
Assert.Equal (15, col);
Assert.Equal (4, row);
- Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry));
- Assert.Equal (15, rx);
- Assert.Equal (4, ry);
+ found = View.FindDeepestView (top, 15, 4);
+ Assert.Equal (top, found);
+ //Assert.Equal (15, found.FrameToScreen ().X);
+ //Assert.Equal (4, found.FrameToScreen ().Y);
}
[Fact]
@@ -1004,30 +1015,31 @@ public class NavigationTests
top.BoundsToScreen (-4, -3, out col, out row);
Assert.Equal (0, col);
Assert.Equal (0, row);
- Assert.Null (View.FindDeepestView (top, -4, -3, out int rx, out int ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
+ var found = View.FindDeepestView (top, -4, -3);
+ Assert.Null (found);
+ //Assert.Equal (0, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
Assert.Equal (Point.Empty, top.ScreenToFrame (3, 2));
top.BoundsToScreen (0, 0, out col, out row);
Assert.Equal (4, col);
Assert.Equal (3, row);
- Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
+ Assert.Equal (top, View.FindDeepestView (top, 3, 2));
+ //Assert.Equal (0, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
Assert.Equal (new Point (10, 0), top.ScreenToFrame (13, 2));
top.BoundsToScreen (10, 0, out col, out row);
Assert.Equal (14, col);
Assert.Equal (3, row);
- Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry));
- Assert.Equal (10, rx);
- Assert.Equal (0, ry);
+ Assert.Equal (top, View.FindDeepestView (top, 13, 2));
+ //Assert.Equal (10, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
Assert.Equal (new Point (11, 1), top.ScreenToFrame (14, 3));
top.BoundsToScreen (11, 1, out col, out row);
Assert.Equal (15, col);
Assert.Equal (4, row);
- Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry));
- Assert.Equal (11, rx);
- Assert.Equal (1, ry);
+ Assert.Equal (top, View.FindDeepestView (top, 14, 3));
+ //Assert.Equal (11, found.FrameToScreen ().X);
+ //Assert.Equal (1, found.FrameToScreen ().Y);
// view
Assert.Equal (new Point (-7, -5), view.ScreenToFrame (0, 0));
@@ -1043,44 +1055,44 @@ public class NavigationTests
view.BoundsToScreen (-6, -4, out col, out row);
Assert.Equal (1, col);
Assert.Equal (1, row);
- Assert.Null (View.FindDeepestView (top, 1, 1, out rx, out ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
+ Assert.Null (View.FindDeepestView (top, 1, 1));
+ //Assert.Equal (0, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
Assert.Equal (new Point (-4, -3), view.ScreenToFrame (3, 2));
view.BoundsToScreen (-3, -2, out col, out row);
Assert.Equal (4, col);
Assert.Equal (3, row);
- Assert.Equal (top, View.FindDeepestView (top, 4, 3, out rx, out ry));
- Assert.Equal (1, rx);
- Assert.Equal (1, ry);
+ Assert.Equal (top, View.FindDeepestView (top, 4, 3));
+ //Assert.Equal (1, found.FrameToScreen ().X);
+ //Assert.Equal (1, found.FrameToScreen ().Y);
Assert.Equal (new Point (-1, -1), view.ScreenToFrame (6, 4));
view.BoundsToScreen (0, 0, out col, out row);
Assert.Equal (7, col);
Assert.Equal (5, row);
- Assert.Equal (view, View.FindDeepestView (top, 7, 5, out rx, out ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
+ Assert.Equal (view, View.FindDeepestView (top, 7, 5));
+ //Assert.Equal (0, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
Assert.Equal (new Point (6, -1), view.ScreenToFrame (13, 4));
view.BoundsToScreen (7, 0, out col, out row);
Assert.Equal (14, col);
Assert.Equal (5, row);
- Assert.Equal (view, View.FindDeepestView (top, 14, 5, out rx, out ry));
- Assert.Equal (7, rx);
- Assert.Equal (0, ry);
+ Assert.Equal (view, View.FindDeepestView (top, 14, 5));
+ //Assert.Equal (7, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
Assert.Equal (new Point (7, -2), view.ScreenToFrame (14, 3));
view.BoundsToScreen (8, -1, out col, out row);
Assert.Equal (15, col);
Assert.Equal (4, row);
- Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry));
- Assert.Equal (12, rx);
- Assert.Equal (2, ry);
+ Assert.Equal (top, View.FindDeepestView (top, 15, 4));
+ //Assert.Equal (12, found.FrameToScreen ().X);
+ //Assert.Equal (2, found.FrameToScreen ().Y);
Assert.Equal (new Point (16, -2), view.ScreenToFrame (23, 3));
view.BoundsToScreen (17, -1, out col, out row);
Assert.Equal (24, col);
Assert.Equal (4, row);
- Assert.Null (View.FindDeepestView (top, 24, 4, out rx, out ry));
- Assert.Equal (0, rx);
- Assert.Equal (0, ry);
+ Assert.Null (View.FindDeepestView (top, 24, 4));
+ //Assert.Equal (0, found.FrameToScreen ().X);
+ //Assert.Equal (0, found.FrameToScreen ().Y);
}
[Fact]
diff --git a/UnitTests/Views/MenuBarTests.cs b/UnitTests/Views/MenuBarTests.cs
index 6910720fd..aa014591a 100644
--- a/UnitTests/Views/MenuBarTests.cs
+++ b/UnitTests/Views/MenuBarTests.cs
@@ -518,7 +518,7 @@ public class MenuBarTests
Application.OnMouseEvent (
new MouseEventEventArgs (
- new MouseEvent { X = 20, Y = 4, Flags = MouseFlags.Button1Clicked }
+ new MouseEvent { X = 20, Y = 5, Flags = MouseFlags.Button1Clicked }
)
);
@@ -555,7 +555,7 @@ public class MenuBarTests
Application.OnMouseEvent (
new MouseEventEventArgs (
- new MouseEvent { X = 20, Y = 4 + i, Flags = MouseFlags.Button1Clicked }
+ new MouseEvent { X = 20, Y = 5 + i, Flags = MouseFlags.Button1Clicked }
)
);