Skip to content

Commit 32e7b63

Browse files
authored
Merge pull request #2065 from BDisp/mouseGrabView-track-feature
Fixes #2064. mouseGrabView must have a track to allow the views who use it having some control.
2 parents 185f4a1 + 10fb8cd commit 32e7b63

File tree

9 files changed

+132
-36
lines changed

9 files changed

+132
-36
lines changed

Terminal.Gui/Core/Application.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,22 @@ static View FindTopFromView (View view)
581581
return top;
582582
}
583583

584-
internal static View mouseGrabView;
584+
static View mouseGrabView;
585+
586+
/// <summary>
587+
/// The view that grabbed the mouse, to where will be routed all the mouse events.
588+
/// </summary>
589+
public static View MouseGrabView => mouseGrabView;
590+
591+
/// <summary>
592+
/// Event to be invoked when a view grab the mouse.
593+
/// </summary>
594+
public static event Action<View> GrabbedMouse;
595+
596+
/// <summary>
597+
/// Event to be invoked when a view ungrab the mouse.
598+
/// </summary>
599+
public static event Action<View> UnGrabbedMouse;
585600

586601
/// <summary>
587602
/// Grabs the mouse, forcing all mouse events to be routed to the specified view until UngrabMouse is called.
@@ -592,6 +607,7 @@ public static void GrabMouse (View view)
592607
{
593608
if (view == null)
594609
return;
610+
OnGrabbedMouse (view);
595611
mouseGrabView = view;
596612
Driver.UncookMouse ();
597613
}
@@ -601,10 +617,27 @@ public static void GrabMouse (View view)
601617
/// </summary>
602618
public static void UngrabMouse ()
603619
{
620+
if (mouseGrabView == null)
621+
return;
622+
OnUnGrabbedMouse (mouseGrabView);
604623
mouseGrabView = null;
605624
Driver.CookMouse ();
606625
}
607626

627+
static void OnGrabbedMouse (View view)
628+
{
629+
if (view == null)
630+
return;
631+
GrabbedMouse?.Invoke (view);
632+
}
633+
634+
static void OnUnGrabbedMouse (View view)
635+
{
636+
if (view == null)
637+
return;
638+
UnGrabbedMouse?.Invoke (view);
639+
}
640+
608641
/// <summary>
609642
/// Merely a debugging aid to see the raw mouse events
610643
/// </summary>
@@ -656,7 +689,7 @@ static void ProcessMouseEvent (MouseEvent me)
656689
lastMouseOwnerView?.OnMouseLeave (me);
657690
}
658691
// System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
659-
if (mouseGrabView != null && mouseGrabView.OnMouseEvent (nme)) {
692+
if (mouseGrabView?.OnMouseEvent (nme) == true) {
660693
return;
661694
}
662695
}

Terminal.Gui/Views/Menu.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,7 @@ public override bool MouseEvent (MouseEvent me)
18161816

18171817
internal bool HandleGrabView (MouseEvent me, View current)
18181818
{
1819-
if (Application.mouseGrabView != null) {
1819+
if (Application.MouseGrabView != null) {
18201820
if (me.View is MenuBar || me.View is Menu) {
18211821
var mbar = GetMouseGrabViewInstance (me.View);
18221822
if (mbar != null) {
@@ -1890,7 +1890,7 @@ internal bool HandleGrabView (MouseEvent me, View current)
18901890
//if (!(me.View is MenuBar) && !(me.View is Menu) && me.Flags != MouseFlags.Button1Pressed))
18911891
// return false;
18921892

1893-
//if (Application.mouseGrabView != null) {
1893+
//if (Application.MouseGrabView != null) {
18941894
// if (me.View is MenuBar || me.View is Menu) {
18951895
// me.X -= me.OfX;
18961896
// me.Y -= me.OfY;
@@ -1905,8 +1905,8 @@ internal bool HandleGrabView (MouseEvent me, View current)
19051905
// return true;
19061906
//}
19071907

1908-
//if (Application.mouseGrabView != null) {
1909-
// if (Application.mouseGrabView == me.View && me.View == current) {
1908+
//if (Application.MouseGrabView != null) {
1909+
// if (Application.MouseGrabView == me.View && me.View == current) {
19101910
// me.X -= me.OfX;
19111911
// me.Y -= me.OfY;
19121912
// } else if (me.View != current && me.View is MenuBar && me.View is Menu) {
@@ -1927,7 +1927,7 @@ internal bool HandleGrabView (MouseEvent me, View current)
19271927

19281928
MenuBar GetMouseGrabViewInstance (View view)
19291929
{
1930-
if (view == null || Application.mouseGrabView == null) {
1930+
if (view == null || Application.MouseGrabView == null) {
19311931
return null;
19321932
}
19331933

@@ -1938,7 +1938,7 @@ MenuBar GetMouseGrabViewInstance (View view)
19381938
hostView = ((Menu)view).host;
19391939
}
19401940

1941-
var grabView = Application.mouseGrabView;
1941+
var grabView = Application.MouseGrabView;
19421942
MenuBar hostGrabView = null;
19431943
if (grabView is MenuBar) {
19441944
hostGrabView = (MenuBar)grabView;

Terminal.Gui/Views/ScrollBarView.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ void ShowHideScrollBars (bool redraw = true)
357357
} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null) {
358358
otherScrollBarView.contentBottomRightCorner.Visible = false;
359359
}
360-
if (Application.mouseGrabView != null && Application.mouseGrabView == this) {
360+
if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
361361
Application.UngrabMouse ();
362362
}
363363
} else if (contentBottomRightCorner != null) {
@@ -638,9 +638,9 @@ public override bool MouseEvent (MouseEvent me)
638638
var pos = Position;
639639

640640
if (me.Flags != MouseFlags.Button1Released
641-
&& (Application.mouseGrabView == null || Application.mouseGrabView != this)) {
641+
&& (Application.MouseGrabView == null || Application.MouseGrabView != this)) {
642642
Application.GrabMouse (this);
643-
} else if (me.Flags == MouseFlags.Button1Released && Application.mouseGrabView != null && Application.mouseGrabView == this) {
643+
} else if (me.Flags == MouseFlags.Button1Released && Application.MouseGrabView != null && Application.MouseGrabView == this) {
644644
lastLocation = -1;
645645
Application.UngrabMouse ();
646646
return true;

Terminal.Gui/Views/ScrollView.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ public override void Add (View view)
227227

228228
void View_MouseLeave (MouseEventArgs e)
229229
{
230-
if (Application.mouseGrabView != null && Application.mouseGrabView != vertical && Application.mouseGrabView != horizontal) {
230+
if (Application.MouseGrabView != null && Application.MouseGrabView != vertical && Application.MouseGrabView != horizontal) {
231231
Application.UngrabMouse ();
232232
}
233233
}

Terminal.Gui/Views/TextField.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,9 @@ void TextField_Initialized (object sender, EventArgs e)
249249
///<inheritdoc/>
250250
public override bool OnLeave (View view)
251251
{
252-
if (Application.mouseGrabView != null && Application.mouseGrabView == this)
252+
if (Application.MouseGrabView != null && Application.MouseGrabView == this)
253253
Application.UngrabMouse ();
254-
//if (SelectedLength != 0 && !(Application.mouseGrabView is MenuBar))
254+
//if (SelectedLength != 0 && !(Application.MouseGrabView is MenuBar))
255255
// ClearAllSelection ();
256256

257257
return base.OnLeave (view);
@@ -1049,7 +1049,7 @@ public override bool MouseEvent (MouseEvent ev)
10491049
int x = PositionCursor (ev);
10501050
isButtonReleased = false;
10511051
PrepareSelection (x);
1052-
if (Application.mouseGrabView == null) {
1052+
if (Application.MouseGrabView == null) {
10531053
Application.GrabMouse (this);
10541054
}
10551055
} else if (ev.Flags == MouseFlags.Button1Released) {

Terminal.Gui/Views/TextView.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4328,7 +4328,7 @@ public override bool MouseEvent (MouseEvent ev)
43284328
}
43294329
lastWasKill = false;
43304330
columnTrack = currentColumn;
4331-
if (Application.mouseGrabView == null) {
4331+
if (Application.MouseGrabView == null) {
43324332
Application.GrabMouse (this);
43334333
}
43344334
} else if (ev.Flags.HasFlag (MouseFlags.Button1Released)) {
@@ -4407,7 +4407,7 @@ void ProcessMouseClick (MouseEvent ev, out List<Rune> line)
44074407
///<inheritdoc/>
44084408
public override bool OnLeave (View view)
44094409
{
4410-
if (Application.mouseGrabView != null && Application.mouseGrabView == this) {
4410+
if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
44114411
Application.UngrabMouse ();
44124412
}
44134413

UnitTests/ApplicationTests.cs

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,7 @@ public void Internal_Tests ()
11441144
Assert.NotNull (Application.Top);
11451145
var rs = Application.Begin (Application.Top);
11461146
Assert.Equal (Application.Top, rs.Toplevel);
1147-
Assert.Null (Application.mouseGrabView);
1147+
Assert.Null (Application.MouseGrabView);
11481148
Assert.Null (Application.WantContinuousButtonPressedView);
11491149
Assert.False (Application.DebugDrawBounds);
11501150
Assert.False (Application.ShowChild (Application.Top));
@@ -1428,7 +1428,7 @@ public void MouseGrabView_WithNullMouseEventView ()
14281428
iterations++;
14291429
if (iterations == 0) {
14301430
Assert.True (tf.HasFocus);
1431-
Assert.Null (Application.mouseGrabView);
1431+
Assert.Null (Application.MouseGrabView);
14321432

14331433
ReflectionTools.InvokePrivate (
14341434
typeof (Application),
@@ -1439,13 +1439,13 @@ public void MouseGrabView_WithNullMouseEventView ()
14391439
Flags = MouseFlags.ReportMousePosition
14401440
});
14411441

1442-
Assert.Equal (sv, Application.mouseGrabView);
1442+
Assert.Equal (sv, Application.MouseGrabView);
14431443

14441444
MessageBox.Query ("Title", "Test", "Ok");
14451445

1446-
Assert.Null (Application.mouseGrabView);
1446+
Assert.Null (Application.MouseGrabView);
14471447
} else if (iterations == 1) {
1448-
Assert.Equal (sv, Application.mouseGrabView);
1448+
Assert.Equal (sv, Application.MouseGrabView);
14491449

14501450
ReflectionTools.InvokePrivate (
14511451
typeof (Application),
@@ -1456,7 +1456,7 @@ public void MouseGrabView_WithNullMouseEventView ()
14561456
Flags = MouseFlags.ReportMousePosition
14571457
});
14581458

1459-
Assert.Null (Application.mouseGrabView);
1459+
Assert.Null (Application.MouseGrabView);
14601460

14611461
ReflectionTools.InvokePrivate (
14621462
typeof (Application),
@@ -1467,7 +1467,7 @@ public void MouseGrabView_WithNullMouseEventView ()
14671467
Flags = MouseFlags.ReportMousePosition
14681468
});
14691469

1470-
Assert.Null (Application.mouseGrabView);
1470+
Assert.Null (Application.MouseGrabView);
14711471

14721472
ReflectionTools.InvokePrivate (
14731473
typeof (Application),
@@ -1478,17 +1478,80 @@ public void MouseGrabView_WithNullMouseEventView ()
14781478
Flags = MouseFlags.Button1Pressed
14791479
});
14801480

1481-
Assert.Null (Application.mouseGrabView);
1481+
Assert.Null (Application.MouseGrabView);
14821482

14831483
Application.RequestStop ();
14841484
} else if (iterations == 2) {
1485-
Assert.Null (Application.mouseGrabView);
1485+
Assert.Null (Application.MouseGrabView);
14861486

14871487
Application.RequestStop ();
14881488
}
14891489
};
14901490

14911491
Application.Run ();
14921492
}
1493+
1494+
[Fact, AutoInitShutdown]
1495+
public void MouseGrabView_GrabbedMouse_UnGrabbedMouse ()
1496+
{
1497+
View grabView = null;
1498+
var count = 0;
1499+
1500+
var view1 = new View ();
1501+
var view2 = new View ();
1502+
1503+
Application.GrabbedMouse += Application_GrabbedMouse;
1504+
Application.UnGrabbedMouse += Application_UnGrabbedMouse;
1505+
1506+
Application.GrabMouse (view1);
1507+
Assert.Equal (0, count);
1508+
Assert.Equal (grabView, view1);
1509+
Assert.Equal (view1, Application.MouseGrabView);
1510+
1511+
Application.UngrabMouse ();
1512+
Assert.Equal (1, count);
1513+
Assert.Equal (grabView, view1);
1514+
Assert.Null (Application.MouseGrabView);
1515+
1516+
Application.GrabbedMouse += Application_GrabbedMouse;
1517+
Application.UnGrabbedMouse += Application_UnGrabbedMouse;
1518+
1519+
Application.GrabMouse (view2);
1520+
Assert.Equal (1, count);
1521+
Assert.Equal (grabView, view2);
1522+
Assert.Equal (view2, Application.MouseGrabView);
1523+
1524+
Application.UngrabMouse ();
1525+
Assert.Equal (2, count);
1526+
Assert.Equal (grabView, view2);
1527+
Assert.Null (Application.MouseGrabView);
1528+
1529+
void Application_GrabbedMouse (View obj)
1530+
{
1531+
if (count == 0) {
1532+
Assert.Equal (view1, obj);
1533+
grabView = view1;
1534+
} else {
1535+
Assert.Equal (view2, obj);
1536+
grabView = view2;
1537+
}
1538+
1539+
Application.GrabbedMouse -= Application_GrabbedMouse;
1540+
}
1541+
1542+
void Application_UnGrabbedMouse (View obj)
1543+
{
1544+
if (count == 0) {
1545+
Assert.Equal (view1, obj);
1546+
Assert.Equal (grabView, obj);
1547+
} else {
1548+
Assert.Equal (view2, obj);
1549+
Assert.Equal (grabView, obj);
1550+
}
1551+
count++;
1552+
1553+
Application.UnGrabbedMouse -= Application_UnGrabbedMouse;
1554+
}
1555+
}
14931556
}
14941557
}

UnitTests/ContextMenuTests.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -519,38 +519,38 @@ public void ContextMenu_Is_Closed_If_Another_MenuBar_Is_Open_Or_Vice_Versa ()
519519

520520
Application.Top.Add (menu);
521521

522-
Assert.Null (Application.mouseGrabView);
522+
Assert.Null (Application.MouseGrabView);
523523

524524
cm.Show ();
525525
Assert.True (ContextMenu.IsShow);
526-
Assert.Equal (cm.MenuBar, Application.mouseGrabView);
526+
Assert.Equal (cm.MenuBar, Application.MouseGrabView);
527527
Assert.False (menu.IsMenuOpen);
528528
Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ())));
529529
Assert.False (ContextMenu.IsShow);
530-
Assert.Equal (menu, Application.mouseGrabView);
530+
Assert.Equal (menu, Application.MouseGrabView);
531531
Assert.True (menu.IsMenuOpen);
532532

533533
cm.Show ();
534534
Assert.True (ContextMenu.IsShow);
535-
Assert.Equal (cm.MenuBar, Application.mouseGrabView);
535+
Assert.Equal (cm.MenuBar, Application.MouseGrabView);
536536
Assert.False (menu.IsMenuOpen);
537537
Assert.False (menu.OnKeyDown (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
538538
Assert.True (menu.OnKeyUp (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
539539
Assert.False (ContextMenu.IsShow);
540-
Assert.Equal (menu, Application.mouseGrabView);
540+
Assert.Equal (menu, Application.MouseGrabView);
541541
Assert.True (menu.IsMenuOpen);
542542

543543
cm.Show ();
544544
Assert.True (ContextMenu.IsShow);
545-
Assert.Equal (cm.MenuBar, Application.mouseGrabView);
545+
Assert.Equal (cm.MenuBar, Application.MouseGrabView);
546546
Assert.False (menu.IsMenuOpen);
547547
Assert.False (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.ReportMousePosition, View = menu }));
548548
Assert.True (ContextMenu.IsShow);
549-
Assert.Equal (cm.MenuBar, Application.mouseGrabView);
549+
Assert.Equal (cm.MenuBar, Application.MouseGrabView);
550550
Assert.False (menu.IsMenuOpen);
551551
Assert.True (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.Button1Clicked, View = menu }));
552552
Assert.False (ContextMenu.IsShow);
553-
Assert.Equal (menu, Application.mouseGrabView);
553+
Assert.Equal (menu, Application.MouseGrabView);
554554
Assert.True (menu.IsMenuOpen);
555555
}
556556

UnitTests/ScrollBarViewTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ This is a test
947947
Flags = MouseFlags.Button1Clicked
948948
});
949949

950-
Assert.Null (Application.mouseGrabView);
950+
Assert.Null (Application.MouseGrabView);
951951
Assert.True (clicked);
952952

953953
clicked = false;
@@ -974,7 +974,7 @@ This is a test
974974
Flags = MouseFlags.Button1Clicked
975975
});
976976

977-
Assert.Null (Application.mouseGrabView);
977+
Assert.Null (Application.MouseGrabView);
978978
Assert.True (clicked);
979979
Assert.Equal (5, sbv.Size);
980980
Assert.False (sbv.ShowScrollIndicator);

0 commit comments

Comments
 (0)