diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs index 6513fd23b..929c13fa8 100644 --- a/Terminal.Gui/Application.cs +++ b/Terminal.Gui/Application.cs @@ -1316,8 +1316,9 @@ public static partial class Application if (!OnUnGrabbingMouse (MouseGrabView)) { - OnUnGrabbedMouse (MouseGrabView); + var view = MouseGrabView; MouseGrabView = null; + OnUnGrabbedMouse (view); } } diff --git a/Terminal.Gui/Views/ScrollView.cs b/Terminal.Gui/Views/ScrollView.cs index 35b213f56..9bc14c3f8 100644 --- a/Terminal.Gui/Views/ScrollView.cs +++ b/Terminal.Gui/Views/ScrollView.cs @@ -78,6 +78,8 @@ public class ScrollView : View _contentView.MouseEnter += View_MouseEnter; _contentView.MouseLeave += View_MouseLeave; + Application.UnGrabbedMouse += Application_UnGrabbedMouse; + // Things this view knows how to do AddCommand (Command.ScrollUp, () => ScrollUp (1)); AddCommand (Command.ScrollDown, () => ScrollDown (1)); @@ -134,6 +136,28 @@ public class ScrollView : View }; } + private void Application_UnGrabbedMouse (object sender, ViewEventArgs e) + { + var parent = e.View is Adornment adornment ? adornment.Parent : e.View; + + if (parent is { }) + { + var supView = parent.SuperView; + + while (supView is { }) + { + if (supView == _contentView) + { + Application.GrabMouse (this); + + break; + } + + supView = supView.SuperView; + } + } + } + /// If true the vertical/horizontal scroll bars won't be showed if it's not needed. public bool AutoHideScrollBars { @@ -536,6 +560,8 @@ public class ScrollView : View _horizontal?.Dispose (); } + Application.UnGrabbedMouse -= Application_UnGrabbedMouse; + base.Dispose (disposing); } @@ -719,7 +745,7 @@ public class ScrollView : View private void View_MouseLeave (object sender, MouseEventEventArgs e) { - if (Application.MouseGrabView is { } && Application.MouseGrabView != _vertical && Application.MouseGrabView != _horizontal) + if (Application.MouseGrabView is { } && Application.MouseGrabView != this && Application.MouseGrabView != _vertical && Application.MouseGrabView != _horizontal) { Application.UngrabMouse (); } diff --git a/UnitTests/Application/MouseTests.cs b/UnitTests/Application/MouseTests.cs index 8c0791070..5c85641b0 100644 --- a/UnitTests/Application/MouseTests.cs +++ b/UnitTests/Application/MouseTests.cs @@ -316,8 +316,9 @@ public class MouseTests View grabView = null; var count = 0; - var view1 = new View (); - var view2 = new View (); + var view1 = new View { Id = "view1" }; + var view2 = new View { Id = "view2" }; + var view3 = new View { Id = "view3" }; Application.GrabbedMouse += Application_GrabbedMouse; Application.UnGrabbedMouse += Application_UnGrabbedMouse; @@ -343,6 +344,8 @@ public class MouseTests Application.UngrabMouse (); Assert.Equal (2, count); Assert.Equal (grabView, view2); + Assert.Equal (view3, Application.MouseGrabView); + Application.UngrabMouse (); Assert.Null (Application.MouseGrabView); void Application_GrabbedMouse (object sender, ViewEventArgs e) @@ -376,6 +379,12 @@ public class MouseTests count++; + if (count > 1) + { + // It's possible to grab another view after the previous was ungrabbed + Application.GrabMouse (view3); + } + Application.UnGrabbedMouse -= Application_UnGrabbedMouse; } } diff --git a/UnitTests/Views/ToplevelTests.cs b/UnitTests/Views/ToplevelTests.cs index 8bc487c70..057ff25f8 100644 --- a/UnitTests/Views/ToplevelTests.cs +++ b/UnitTests/Views/ToplevelTests.cs @@ -1366,7 +1366,6 @@ public class ToplevelTests Assert.Equal (new (0, 0, 10, 5), view._needsDisplayRect); } - // BUGBUG: Broke this test with #2483 - @bdisp I need your help figuring out why [Fact] [AutoInitShutdown] public void Toplevel_Inside_ScrollView_MouseGrabView () @@ -1471,44 +1470,44 @@ public class ToplevelTests Assert.Equal (win.Border, Application.MouseGrabView); top.SetNeedsLayout (); top.LayoutSubviews (); - // BUGBUG: tig broke this in #3273 - // Assert.Equal (new Rectangle (2, 2, 195, 95), win.Frame); - // Application.Refresh (); + Assert.Equal (new Rectangle (2, 2, 195, 95), win.Frame); + Application.Refresh (); - // TestHelpers.AssertDriverContentsWithFrameAre ( - // @" - // ▲ - // ┬ - // ┌────────────────────────────────────│ - // │ ┴ - // │ ░ - // │ ░ - // │ ░ - // │ ░ - // │ ░ - // │ ░ - // │ ░ - // │ ░ - // │ ░ - // │ ░ - // │ ▼ - //◄├──────┤░░░░░░░░░░░░░░░░░░░░░░░░░░░░░► ", - // _output - // ); + TestHelpers.AssertDriverContentsWithFrameAre ( + @" + ▲ + ┬ + ┌────────────────────────────────────│ + │ ┴ + │ ░ + │ ░ + │ ░ + │ ░ + │ ░ + │ ░ + │ ░ + │ ░ + │ ░ + │ ░ + │ ▼ + ◄├──────┤░░░░░░░░░░░░░░░░░░░░░░░░░░░░░► ", + _output + ); - // Application.OnMouseEvent ( - // new MouseEventEventArgs ( - // new MouseEvent { X = 5, Y = 5, Flags = MouseFlags.Button1Released } - // ) - // ); - // Assert.Null (Application.MouseGrabView); + Application.OnMouseEvent ( + new MouseEventEventArgs ( + new MouseEvent { X = 5, Y = 5, Flags = MouseFlags.Button1Released } + ) + ); + // ScrollView always grab the mouse when the container's subview OnMouseEnter don't want grab the mouse + Assert.Equal (scrollView, Application.MouseGrabView); - // Application.OnMouseEvent ( - // new MouseEventEventArgs ( - // new MouseEvent { X = 4, Y = 4, Flags = MouseFlags.ReportMousePosition } - // ) - // ); - // Assert.Equal (scrollView, Application.MouseGrabView); + Application.OnMouseEvent ( + new MouseEventEventArgs ( + new MouseEvent { X = 4, Y = 4, Flags = MouseFlags.ReportMousePosition } + ) + ); + Assert.Equal (scrollView, Application.MouseGrabView); } [Fact]