Преглед на файлове

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.
Tig Kindel преди 2 години
родител
ревизия
32e7b63b77

+ 35 - 2
Terminal.Gui/Core/Application.cs

@@ -581,7 +581,22 @@ namespace Terminal.Gui {
 			return top;
 			return top;
 		}
 		}
 
 
-		internal static View mouseGrabView;
+		static View mouseGrabView;
+
+		/// <summary>
+		/// The view that grabbed the mouse, to where will be routed all the mouse events.
+		/// </summary>
+		public static View MouseGrabView => mouseGrabView;
+
+		/// <summary>
+		/// Event to be invoked when a view grab the mouse.
+		/// </summary>
+		public static event Action<View> GrabbedMouse;
+
+		/// <summary>
+		/// Event to be invoked when a view ungrab the mouse.
+		/// </summary>
+		public static event Action<View> UnGrabbedMouse;
 
 
 		/// <summary>
 		/// <summary>
 		/// Grabs the mouse, forcing all mouse events to be routed to the specified view until UngrabMouse is called.
 		/// Grabs the mouse, forcing all mouse events to be routed to the specified view until UngrabMouse is called.
@@ -592,6 +607,7 @@ namespace Terminal.Gui {
 		{
 		{
 			if (view == null)
 			if (view == null)
 				return;
 				return;
+			OnGrabbedMouse (view);
 			mouseGrabView = view;
 			mouseGrabView = view;
 			Driver.UncookMouse ();
 			Driver.UncookMouse ();
 		}
 		}
@@ -601,10 +617,27 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public static void UngrabMouse ()
 		public static void UngrabMouse ()
 		{
 		{
+			if (mouseGrabView == null)
+				return;
+			OnUnGrabbedMouse (mouseGrabView);
 			mouseGrabView = null;
 			mouseGrabView = null;
 			Driver.CookMouse ();
 			Driver.CookMouse ();
 		}
 		}
 
 
+		static void OnGrabbedMouse (View view)
+		{
+			if (view == null)
+				return;
+			GrabbedMouse?.Invoke (view);
+		}
+
+		static void OnUnGrabbedMouse (View view)
+		{
+			if (view == null)
+				return;
+			UnGrabbedMouse?.Invoke (view);
+		}
+
 		/// <summary>
 		/// <summary>
 		/// Merely a debugging aid to see the raw mouse events
 		/// Merely a debugging aid to see the raw mouse events
 		/// </summary>
 		/// </summary>
@@ -656,7 +689,7 @@ namespace Terminal.Gui {
 					lastMouseOwnerView?.OnMouseLeave (me);
 					lastMouseOwnerView?.OnMouseLeave (me);
 				}
 				}
 				// System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
 				// System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
-				if (mouseGrabView != null && mouseGrabView.OnMouseEvent (nme)) {
+				if (mouseGrabView?.OnMouseEvent (nme) == true) {
 					return;
 					return;
 				}
 				}
 			}
 			}

+ 6 - 6
Terminal.Gui/Views/Menu.cs

@@ -1816,7 +1816,7 @@ namespace Terminal.Gui {
 
 
 		internal bool HandleGrabView (MouseEvent me, View current)
 		internal bool HandleGrabView (MouseEvent me, View current)
 		{
 		{
-			if (Application.mouseGrabView != null) {
+			if (Application.MouseGrabView != null) {
 				if (me.View is MenuBar || me.View is Menu) {
 				if (me.View is MenuBar || me.View is Menu) {
 					var mbar = GetMouseGrabViewInstance (me.View);
 					var mbar = GetMouseGrabViewInstance (me.View);
 					if (mbar != null) {
 					if (mbar != null) {
@@ -1890,7 +1890,7 @@ namespace Terminal.Gui {
 			//if (!(me.View is MenuBar) && !(me.View is Menu) && me.Flags != MouseFlags.Button1Pressed))
 			//if (!(me.View is MenuBar) && !(me.View is Menu) && me.Flags != MouseFlags.Button1Pressed))
 			//	return false;
 			//	return false;
 
 
-			//if (Application.mouseGrabView != null) {
+			//if (Application.MouseGrabView != null) {
 			//	if (me.View is MenuBar || me.View is Menu) {
 			//	if (me.View is MenuBar || me.View is Menu) {
 			//		me.X -= me.OfX;
 			//		me.X -= me.OfX;
 			//		me.Y -= me.OfY;
 			//		me.Y -= me.OfY;
@@ -1905,8 +1905,8 @@ namespace Terminal.Gui {
 			//	return true;
 			//	return true;
 			//}
 			//}
 
 
-			//if (Application.mouseGrabView != null) {
-			//	if (Application.mouseGrabView == me.View && me.View == current) {
+			//if (Application.MouseGrabView != null) {
+			//	if (Application.MouseGrabView == me.View && me.View == current) {
 			//		me.X -= me.OfX;
 			//		me.X -= me.OfX;
 			//		me.Y -= me.OfY;
 			//		me.Y -= me.OfY;
 			//	} else if (me.View != current && me.View is MenuBar && me.View is Menu) {
 			//	} else if (me.View != current && me.View is MenuBar && me.View is Menu) {
@@ -1927,7 +1927,7 @@ namespace Terminal.Gui {
 
 
 		MenuBar GetMouseGrabViewInstance (View view)
 		MenuBar GetMouseGrabViewInstance (View view)
 		{
 		{
-			if (view == null || Application.mouseGrabView == null) {
+			if (view == null || Application.MouseGrabView == null) {
 				return null;
 				return null;
 			}
 			}
 
 
@@ -1938,7 +1938,7 @@ namespace Terminal.Gui {
 				hostView = ((Menu)view).host;
 				hostView = ((Menu)view).host;
 			}
 			}
 
 
-			var grabView = Application.mouseGrabView;
+			var grabView = Application.MouseGrabView;
 			MenuBar hostGrabView = null;
 			MenuBar hostGrabView = null;
 			if (grabView is MenuBar) {
 			if (grabView is MenuBar) {
 				hostGrabView = (MenuBar)grabView;
 				hostGrabView = (MenuBar)grabView;

+ 3 - 3
Terminal.Gui/Views/ScrollBarView.cs

@@ -357,7 +357,7 @@ namespace Terminal.Gui {
 				} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null) {
 				} else if (otherScrollBarView != null && otherScrollBarView.contentBottomRightCorner != null) {
 					otherScrollBarView.contentBottomRightCorner.Visible = false;
 					otherScrollBarView.contentBottomRightCorner.Visible = false;
 				}
 				}
-				if (Application.mouseGrabView != null && Application.mouseGrabView == this) {
+				if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
 					Application.UngrabMouse ();
 					Application.UngrabMouse ();
 				}
 				}
 			} else if (contentBottomRightCorner != null) {
 			} else if (contentBottomRightCorner != null) {
@@ -638,9 +638,9 @@ namespace Terminal.Gui {
 			var pos = Position;
 			var pos = Position;
 
 
 			if (me.Flags != MouseFlags.Button1Released
 			if (me.Flags != MouseFlags.Button1Released
-				&& (Application.mouseGrabView == null || Application.mouseGrabView != this)) {
+				&& (Application.MouseGrabView == null || Application.MouseGrabView != this)) {
 				Application.GrabMouse (this);
 				Application.GrabMouse (this);
-			} else if (me.Flags == MouseFlags.Button1Released && Application.mouseGrabView != null && Application.mouseGrabView == this) {
+			} else if (me.Flags == MouseFlags.Button1Released && Application.MouseGrabView != null && Application.MouseGrabView == this) {
 				lastLocation = -1;
 				lastLocation = -1;
 				Application.UngrabMouse ();
 				Application.UngrabMouse ();
 				return true;
 				return true;

+ 1 - 1
Terminal.Gui/Views/ScrollView.cs

@@ -227,7 +227,7 @@ namespace Terminal.Gui {
 
 
 		void View_MouseLeave (MouseEventArgs e)
 		void View_MouseLeave (MouseEventArgs e)
 		{
 		{
-			if (Application.mouseGrabView != null && Application.mouseGrabView != vertical && Application.mouseGrabView != horizontal) {
+			if (Application.MouseGrabView != null && Application.MouseGrabView != vertical && Application.MouseGrabView != horizontal) {
 				Application.UngrabMouse ();
 				Application.UngrabMouse ();
 			}
 			}
 		}
 		}

+ 3 - 3
Terminal.Gui/Views/TextField.cs

@@ -249,9 +249,9 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override bool OnLeave (View view)
 		public override bool OnLeave (View view)
 		{
 		{
-			if (Application.mouseGrabView != null && Application.mouseGrabView == this)
+			if (Application.MouseGrabView != null && Application.MouseGrabView == this)
 				Application.UngrabMouse ();
 				Application.UngrabMouse ();
-			//if (SelectedLength != 0 && !(Application.mouseGrabView is MenuBar))
+			//if (SelectedLength != 0 && !(Application.MouseGrabView is MenuBar))
 			//	ClearAllSelection ();
 			//	ClearAllSelection ();
 
 
 			return base.OnLeave (view);
 			return base.OnLeave (view);
@@ -1049,7 +1049,7 @@ namespace Terminal.Gui {
 				int x = PositionCursor (ev);
 				int x = PositionCursor (ev);
 				isButtonReleased = false;
 				isButtonReleased = false;
 				PrepareSelection (x);
 				PrepareSelection (x);
-				if (Application.mouseGrabView == null) {
+				if (Application.MouseGrabView == null) {
 					Application.GrabMouse (this);
 					Application.GrabMouse (this);
 				}
 				}
 			} else if (ev.Flags == MouseFlags.Button1Released) {
 			} else if (ev.Flags == MouseFlags.Button1Released) {

+ 2 - 2
Terminal.Gui/Views/TextView.cs

@@ -4328,7 +4328,7 @@ namespace Terminal.Gui {
 				}
 				}
 				lastWasKill = false;
 				lastWasKill = false;
 				columnTrack = currentColumn;
 				columnTrack = currentColumn;
-				if (Application.mouseGrabView == null) {
+				if (Application.MouseGrabView == null) {
 					Application.GrabMouse (this);
 					Application.GrabMouse (this);
 				}
 				}
 			} else if (ev.Flags.HasFlag (MouseFlags.Button1Released)) {
 			} else if (ev.Flags.HasFlag (MouseFlags.Button1Released)) {
@@ -4407,7 +4407,7 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override bool OnLeave (View view)
 		public override bool OnLeave (View view)
 		{
 		{
-			if (Application.mouseGrabView != null && Application.mouseGrabView == this) {
+			if (Application.MouseGrabView != null && Application.MouseGrabView == this) {
 				Application.UngrabMouse ();
 				Application.UngrabMouse ();
 			}
 			}
 
 

+ 72 - 9
UnitTests/ApplicationTests.cs

@@ -1144,7 +1144,7 @@ namespace Terminal.Gui.Core {
 			Assert.NotNull (Application.Top);
 			Assert.NotNull (Application.Top);
 			var rs = Application.Begin (Application.Top);
 			var rs = Application.Begin (Application.Top);
 			Assert.Equal (Application.Top, rs.Toplevel);
 			Assert.Equal (Application.Top, rs.Toplevel);
-			Assert.Null (Application.mouseGrabView);
+			Assert.Null (Application.MouseGrabView);
 			Assert.Null (Application.WantContinuousButtonPressedView);
 			Assert.Null (Application.WantContinuousButtonPressedView);
 			Assert.False (Application.DebugDrawBounds);
 			Assert.False (Application.DebugDrawBounds);
 			Assert.False (Application.ShowChild (Application.Top));
 			Assert.False (Application.ShowChild (Application.Top));
@@ -1428,7 +1428,7 @@ namespace Terminal.Gui.Core {
 				iterations++;
 				iterations++;
 				if (iterations == 0) {
 				if (iterations == 0) {
 					Assert.True (tf.HasFocus);
 					Assert.True (tf.HasFocus);
-					Assert.Null (Application.mouseGrabView);
+					Assert.Null (Application.MouseGrabView);
 
 
 					ReflectionTools.InvokePrivate (
 					ReflectionTools.InvokePrivate (
 						typeof (Application),
 						typeof (Application),
@@ -1439,13 +1439,13 @@ namespace Terminal.Gui.Core {
 							Flags = MouseFlags.ReportMousePosition
 							Flags = MouseFlags.ReportMousePosition
 						});
 						});
 
 
-					Assert.Equal (sv, Application.mouseGrabView);
+					Assert.Equal (sv, Application.MouseGrabView);
 
 
 					MessageBox.Query ("Title", "Test", "Ok");
 					MessageBox.Query ("Title", "Test", "Ok");
 
 
-					Assert.Null (Application.mouseGrabView);
+					Assert.Null (Application.MouseGrabView);
 				} else if (iterations == 1) {
 				} else if (iterations == 1) {
-					Assert.Equal (sv, Application.mouseGrabView);
+					Assert.Equal (sv, Application.MouseGrabView);
 
 
 					ReflectionTools.InvokePrivate (
 					ReflectionTools.InvokePrivate (
 						typeof (Application),
 						typeof (Application),
@@ -1456,7 +1456,7 @@ namespace Terminal.Gui.Core {
 							Flags = MouseFlags.ReportMousePosition
 							Flags = MouseFlags.ReportMousePosition
 						});
 						});
 
 
-					Assert.Null (Application.mouseGrabView);
+					Assert.Null (Application.MouseGrabView);
 
 
 					ReflectionTools.InvokePrivate (
 					ReflectionTools.InvokePrivate (
 						typeof (Application),
 						typeof (Application),
@@ -1467,7 +1467,7 @@ namespace Terminal.Gui.Core {
 							Flags = MouseFlags.ReportMousePosition
 							Flags = MouseFlags.ReportMousePosition
 						});
 						});
 
 
-					Assert.Null (Application.mouseGrabView);
+					Assert.Null (Application.MouseGrabView);
 
 
 					ReflectionTools.InvokePrivate (
 					ReflectionTools.InvokePrivate (
 						typeof (Application),
 						typeof (Application),
@@ -1478,11 +1478,11 @@ namespace Terminal.Gui.Core {
 							Flags = MouseFlags.Button1Pressed
 							Flags = MouseFlags.Button1Pressed
 						});
 						});
 
 
-					Assert.Null (Application.mouseGrabView);
+					Assert.Null (Application.MouseGrabView);
 
 
 					Application.RequestStop ();
 					Application.RequestStop ();
 				} else if (iterations == 2) {
 				} else if (iterations == 2) {
-					Assert.Null (Application.mouseGrabView);
+					Assert.Null (Application.MouseGrabView);
 
 
 					Application.RequestStop ();
 					Application.RequestStop ();
 				}
 				}
@@ -1490,5 +1490,68 @@ namespace Terminal.Gui.Core {
 
 
 			Application.Run ();
 			Application.Run ();
 		}
 		}
+
+		[Fact, AutoInitShutdown]
+		public void MouseGrabView_GrabbedMouse_UnGrabbedMouse ()
+		{
+			View grabView = null;
+			var count = 0;
+
+			var view1 = new View ();
+			var view2 = new View ();
+
+			Application.GrabbedMouse += Application_GrabbedMouse;
+			Application.UnGrabbedMouse += Application_UnGrabbedMouse;
+
+			Application.GrabMouse (view1);
+			Assert.Equal (0, count);
+			Assert.Equal (grabView, view1);
+			Assert.Equal (view1, Application.MouseGrabView);
+
+			Application.UngrabMouse ();
+			Assert.Equal (1, count);
+			Assert.Equal (grabView, view1);
+			Assert.Null (Application.MouseGrabView);
+
+			Application.GrabbedMouse += Application_GrabbedMouse;
+			Application.UnGrabbedMouse += Application_UnGrabbedMouse;
+
+			Application.GrabMouse (view2);
+			Assert.Equal (1, count);
+			Assert.Equal (grabView, view2);
+			Assert.Equal (view2, Application.MouseGrabView);
+
+			Application.UngrabMouse ();
+			Assert.Equal (2, count);
+			Assert.Equal (grabView, view2);
+			Assert.Null (Application.MouseGrabView);
+
+			void Application_GrabbedMouse (View obj)
+			{
+				if (count == 0) {
+					Assert.Equal (view1, obj);
+					grabView = view1;
+				} else {
+					Assert.Equal (view2, obj);
+					grabView = view2;
+				}
+
+				Application.GrabbedMouse -= Application_GrabbedMouse;
+			}
+
+			void Application_UnGrabbedMouse (View obj)
+			{
+				if (count == 0) {
+					Assert.Equal (view1, obj);
+					Assert.Equal (grabView, obj);
+				} else {
+					Assert.Equal (view2, obj);
+					Assert.Equal (grabView, obj);
+				}
+				count++;
+
+				Application.UnGrabbedMouse -= Application_UnGrabbedMouse;
+			}
+		}
 	}
 	}
 }
 }

+ 8 - 8
UnitTests/ContextMenuTests.cs

@@ -519,38 +519,38 @@ namespace Terminal.Gui.Core {
 
 
 			Application.Top.Add (menu);
 			Application.Top.Add (menu);
 
 
-			Assert.Null (Application.mouseGrabView);
+			Assert.Null (Application.MouseGrabView);
 
 
 			cm.Show ();
 			cm.Show ();
 			Assert.True (ContextMenu.IsShow);
 			Assert.True (ContextMenu.IsShow);
-			Assert.Equal (cm.MenuBar, Application.mouseGrabView);
+			Assert.Equal (cm.MenuBar, Application.MouseGrabView);
 			Assert.False (menu.IsMenuOpen);
 			Assert.False (menu.IsMenuOpen);
 			Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ())));
 			Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ())));
 			Assert.False (ContextMenu.IsShow);
 			Assert.False (ContextMenu.IsShow);
-			Assert.Equal (menu, Application.mouseGrabView);
+			Assert.Equal (menu, Application.MouseGrabView);
 			Assert.True (menu.IsMenuOpen);
 			Assert.True (menu.IsMenuOpen);
 
 
 			cm.Show ();
 			cm.Show ();
 			Assert.True (ContextMenu.IsShow);
 			Assert.True (ContextMenu.IsShow);
-			Assert.Equal (cm.MenuBar, Application.mouseGrabView);
+			Assert.Equal (cm.MenuBar, Application.MouseGrabView);
 			Assert.False (menu.IsMenuOpen);
 			Assert.False (menu.IsMenuOpen);
 			Assert.False (menu.OnKeyDown (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
 			Assert.False (menu.OnKeyDown (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
 			Assert.True (menu.OnKeyUp (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
 			Assert.True (menu.OnKeyUp (new KeyEvent (Key.Null, new KeyModifiers () { Alt = true })));
 			Assert.False (ContextMenu.IsShow);
 			Assert.False (ContextMenu.IsShow);
-			Assert.Equal (menu, Application.mouseGrabView);
+			Assert.Equal (menu, Application.MouseGrabView);
 			Assert.True (menu.IsMenuOpen);
 			Assert.True (menu.IsMenuOpen);
 
 
 			cm.Show ();
 			cm.Show ();
 			Assert.True (ContextMenu.IsShow);
 			Assert.True (ContextMenu.IsShow);
-			Assert.Equal (cm.MenuBar, Application.mouseGrabView);
+			Assert.Equal (cm.MenuBar, Application.MouseGrabView);
 			Assert.False (menu.IsMenuOpen);
 			Assert.False (menu.IsMenuOpen);
 			Assert.False (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.ReportMousePosition, View = menu }));
 			Assert.False (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.ReportMousePosition, View = menu }));
 			Assert.True (ContextMenu.IsShow);
 			Assert.True (ContextMenu.IsShow);
-			Assert.Equal (cm.MenuBar, Application.mouseGrabView);
+			Assert.Equal (cm.MenuBar, Application.MouseGrabView);
 			Assert.False (menu.IsMenuOpen);
 			Assert.False (menu.IsMenuOpen);
 			Assert.True (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.Button1Clicked, View = menu }));
 			Assert.True (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.Button1Clicked, View = menu }));
 			Assert.False (ContextMenu.IsShow);
 			Assert.False (ContextMenu.IsShow);
-			Assert.Equal (menu, Application.mouseGrabView);
+			Assert.Equal (menu, Application.MouseGrabView);
 			Assert.True (menu.IsMenuOpen);
 			Assert.True (menu.IsMenuOpen);
 		}
 		}
 
 

+ 2 - 2
UnitTests/ScrollBarViewTests.cs

@@ -947,7 +947,7 @@ This is a test
 					Flags = MouseFlags.Button1Clicked
 					Flags = MouseFlags.Button1Clicked
 				});
 				});
 
 
-			Assert.Null (Application.mouseGrabView);
+			Assert.Null (Application.MouseGrabView);
 			Assert.True (clicked);
 			Assert.True (clicked);
 
 
 			clicked = false;
 			clicked = false;
@@ -974,7 +974,7 @@ This is a test
 					Flags = MouseFlags.Button1Clicked
 					Flags = MouseFlags.Button1Clicked
 				});
 				});
 
 
-			Assert.Null (Application.mouseGrabView);
+			Assert.Null (Application.MouseGrabView);
 			Assert.True (clicked);
 			Assert.True (clicked);
 			Assert.Equal (5, sbv.Size);
 			Assert.Equal (5, sbv.Size);
 			Assert.False (sbv.ShowScrollIndicator);
 			Assert.False (sbv.ShowScrollIndicator);