Tig hai 10 meses
pai
achega
dfde8f6617

+ 54 - 44
Terminal.Gui/Application/Application.Mouse.cs

@@ -118,9 +118,6 @@ public static partial class Application // Mouse handling
         UnGrabbedMouse?.Invoke (view, new (view));
         UnGrabbedMouse?.Invoke (view, new (view));
     }
     }
 
 
-    // Used by OnMouseEvent to suppport MouseEnter and MouseLeave events
-    internal static List<View?> ViewsUnderMouse { get; } = new ();
-
     /// <summary>Event fired when a mouse move or click occurs. Coordinates are screen relative.</summary>
     /// <summary>Event fired when a mouse move or click occurs. Coordinates are screen relative.</summary>
     /// <remarks>
     /// <remarks>
     ///     <para>
     ///     <para>
@@ -163,45 +160,9 @@ public static partial class Application // Mouse handling
             return;
             return;
         }
         }
 
 
-        if (MouseGrabView is { })
+        if (GrabMouse (deepestViewUnderMouse, mouseEvent))
         {
         {
-
-#if DEBUG_IDISPOSABLE
-            if (MouseGrabView.WasDisposed)
-            {
-                throw new ObjectDisposedException (MouseGrabView.GetType ().FullName);
-            }
-#endif
-            // If the mouse is grabbed, send the event to the view that grabbed it.
-            // The coordinates are relative to the Bounds of the view that grabbed the mouse.
-            Point frameLoc = MouseGrabView.ScreenToViewport (mouseEvent.Position);
-
-            var viewRelativeMouseEvent = new MouseEvent
-            {
-                Position = frameLoc,
-                Flags = mouseEvent.Flags,
-                ScreenPosition = mouseEvent.Position,
-                View = deepestViewUnderMouse ?? MouseGrabView
-            };
-
-            if ((MouseGrabView.Viewport with { Location = Point.Empty }).Contains (viewRelativeMouseEvent.Position) is false)
-            {
-                // The mouse has moved outside the bounds of the view that grabbed the mouse
-                //MouseGrabView.NewMouseLeaveEvent (mouseEvent);
-            }
-
-            //System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
-            if (MouseGrabView?.NewMouseEvent (viewRelativeMouseEvent) is true)
-            {
-                return;
-            }
-
-            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
-            if (MouseGrabView is null && deepestViewUnderMouse is Adornment)
-            {
-                // The view that grabbed the mouse has been disposed
-                return;
-            }
+            return;
         }
         }
 
 
         // We can combine this into the switch expression to reduce cognitive complexity even more and likely
         // We can combine this into the switch expression to reduce cognitive complexity even more and likely
@@ -220,6 +181,7 @@ public static partial class Application // Mouse handling
             return;
             return;
         }
         }
 
 
+        // TODO: Move this after call to RaiseMouseEnterLeaveEvents once MouseEnter/Leave don't use MouseEvent anymore.
         MouseEvent? me;
         MouseEvent? me;
 
 
         if (deepestViewUnderMouse is Adornment adornment)
         if (deepestViewUnderMouse is Adornment adornment)
@@ -292,11 +254,59 @@ public static partial class Application // Mouse handling
         ApplicationOverlapped.BringOverlappedTopToFront ();
         ApplicationOverlapped.BringOverlappedTopToFront ();
     }
     }
 
 
+    internal static bool GrabMouse (View? deepestViewUnderMouse, MouseEvent mouseEvent)
+    {
+        if (MouseGrabView is { })
+        {
+
+#if DEBUG_IDISPOSABLE
+            if (MouseGrabView.WasDisposed)
+            {
+                throw new ObjectDisposedException (MouseGrabView.GetType ().FullName);
+            }
+#endif
+            // If the mouse is grabbed, send the event to the view that grabbed it.
+            // The coordinates are relative to the Bounds of the view that grabbed the mouse.
+            Point frameLoc = MouseGrabView.ScreenToViewport (mouseEvent.Position);
+
+            var viewRelativeMouseEvent = new MouseEvent
+            {
+                Position = frameLoc,
+                Flags = mouseEvent.Flags,
+                ScreenPosition = mouseEvent.Position,
+                View = deepestViewUnderMouse ?? MouseGrabView
+            };
+
+            //System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
+            if (MouseGrabView?.NewMouseEvent (viewRelativeMouseEvent) is true)
+            {
+                return true;
+            }
+
+            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
+            if (MouseGrabView is null && deepestViewUnderMouse is Adornment)
+            {
+                // The view that grabbed the mouse has been disposed
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    internal static readonly List<View?> _cachedViewsUnderMouse = new ();
+
     // TODO: Refactor MouseEnter/LeaveEvents to not take MouseEvent param.
     // TODO: Refactor MouseEnter/LeaveEvents to not take MouseEvent param.
+    /// <summary>
+    ///     INTERNAL: Raises the MouseEnter and MouseLeave events for the views that are under the mouse.
+    /// </summary>
+    /// <param name="screenPosition">The position of the mouse.</param>
+    /// <param name="currentViewsUnderMouse">The most recent result from GetViewsUnderMouse().</param>
+    /// <param name="me">TODO: Remove once MouseEnter/Leave don't use MouseEvent anymore.</param>
     internal static void RaiseMouseEnterLeaveEvents (Point screenPosition, List<View?> currentViewsUnderMouse, MouseEvent me)
     internal static void RaiseMouseEnterLeaveEvents (Point screenPosition, List<View?> currentViewsUnderMouse, MouseEvent me)
     {
     {
         // Tell any views that are no longer under the mouse that the mouse has left
         // Tell any views that are no longer under the mouse that the mouse has left
-        List<View?> viewsToLeave = ViewsUnderMouse.Where (v => v is { } && !currentViewsUnderMouse.Contains (v)).ToList ();
+        List<View?> viewsToLeave = _cachedViewsUnderMouse.Where (v => v is { } && !currentViewsUnderMouse.Contains (v)).ToList ();
         foreach (View? view in viewsToLeave)
         foreach (View? view in viewsToLeave)
         {
         {
             if (view is null)
             if (view is null)
@@ -322,7 +332,7 @@ public static partial class Application // Mouse handling
             }
             }
         }
         }
 
 
-        ViewsUnderMouse.Clear ();
+        _cachedViewsUnderMouse.Clear ();
 
 
         // Tell any views that are now under the mouse that the mouse has entered and add them to the list
         // Tell any views that are now under the mouse that the mouse has entered and add them to the list
         foreach (View? view in currentViewsUnderMouse)
         foreach (View? view in currentViewsUnderMouse)
@@ -332,7 +342,7 @@ public static partial class Application // Mouse handling
                 continue;
                 continue;
             }
             }
 
 
-            ViewsUnderMouse.Add (view);
+            _cachedViewsUnderMouse.Add (view);
 
 
             if (view is Adornment adornmentView)
             if (view is Adornment adornmentView)
             {
             {

+ 1 - 1
Terminal.Gui/Application/Application.cs

@@ -198,7 +198,7 @@ public static partial class Application
         IsInitialized = false;
         IsInitialized = false;
 
 
         // Mouse
         // Mouse
-        ViewsUnderMouse.Clear ();
+        _cachedViewsUnderMouse.Clear ();
         WantContinuousButtonPressedView = null;
         WantContinuousButtonPressedView = null;
         MouseEvent = null;
         MouseEvent = null;
         GrabbedMouse = null;
         GrabbedMouse = null;

+ 3 - 3
UnitTests/Application/ApplicationTests.cs

@@ -317,7 +317,7 @@ public class ApplicationTests
             Assert.False (Application._forceFakeConsole);
             Assert.False (Application._forceFakeConsole);
             Assert.Equal (-1, Application.MainThreadId);
             Assert.Equal (-1, Application.MainThreadId);
             Assert.Empty (Application.TopLevels);
             Assert.Empty (Application.TopLevels);
-            Assert.Empty (Application.ViewsUnderMouse);
+            Assert.Empty (Application._cachedViewsUnderMouse);
 
 
             // Keyboard
             // Keyboard
             Assert.Empty (Application.GetViewKeyBindings ());
             Assert.Empty (Application.GetViewKeyBindings ());
@@ -347,7 +347,7 @@ public class ApplicationTests
         Application.MainThreadId = 1;
         Application.MainThreadId = 1;
 
 
         //Application._topLevels = new List<Toplevel> ();
         //Application._topLevels = new List<Toplevel> ();
-        Application.ViewsUnderMouse.Clear ();
+        Application._cachedViewsUnderMouse.Clear ();
 
 
         //Application.SupportedCultures = new List<CultureInfo> ();
         //Application.SupportedCultures = new List<CultureInfo> ();
         Application.Force16Colors = true;
         Application.Force16Colors = true;
@@ -361,7 +361,7 @@ public class ApplicationTests
 
 
         //ApplicationOverlapped.OverlappedChildren = new List<View> ();
         //ApplicationOverlapped.OverlappedChildren = new List<View> ();
         //ApplicationOverlapped.OverlappedTop = 
         //ApplicationOverlapped.OverlappedTop = 
-        Application.ViewsUnderMouse.Clear ();
+        Application._cachedViewsUnderMouse.Clear ();
 
 
         //Application.WantContinuousButtonPressedView = new View ();
         //Application.WantContinuousButtonPressedView = new View ();
 
 

+ 4 - 4
UnitTests/Views/ContextMenuTests.cs

@@ -1394,7 +1394,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (tf1.HasFocus);
         Assert.True (tf1.HasFocus);
         Assert.False (tf2.HasFocus);
         Assert.False (tf2.HasFocus);
         Assert.Equal (4, win.Subviews.Count); // TF & TV add autocomplete popup's to their superviews.
         Assert.Equal (4, win.Subviews.Count); // TF & TV add autocomplete popup's to their superviews.
-        Assert.Empty (Application.ViewsUnderMouse);
+        Assert.Empty (Application._cachedViewsUnderMouse);
 
 
         // Right click on tf2 to open context menu
         // Right click on tf2 to open context menu
         Application.OnMouseEvent (new () { Position = new (1, 3), Flags = MouseFlags.Button3Clicked });
         Application.OnMouseEvent (new () { Position = new (1, 3), Flags = MouseFlags.Button3Clicked });
@@ -1404,7 +1404,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.True (tf2.ContextMenu.MenuBar.IsMenuOpen);
         Assert.True (tf2.ContextMenu.MenuBar.IsMenuOpen);
         Assert.True (win.Focused is Menu);
         Assert.True (win.Focused is Menu);
         Assert.True (Application.MouseGrabView is MenuBar);
         Assert.True (Application.MouseGrabView is MenuBar);
-        Assert.Equal (tf2, Application.ViewsUnderMouse.LastOrDefault ());
+        Assert.Equal (tf2, Application._cachedViewsUnderMouse.LastOrDefault ());
 
 
         // Click on tf1 to focus it, which cause context menu being closed
         // Click on tf1 to focus it, which cause context menu being closed
         Application.OnMouseEvent (new () { Position = new (1, 1), Flags = MouseFlags.Button1Clicked });
         Application.OnMouseEvent (new () { Position = new (1, 1), Flags = MouseFlags.Button1Clicked });
@@ -1416,7 +1416,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.NotNull (tf2.ContextMenu.MenuBar);
         Assert.NotNull (tf2.ContextMenu.MenuBar);
         Assert.Equal (win.Focused, tf1);
         Assert.Equal (win.Focused, tf1);
         Assert.Null (Application.MouseGrabView);
         Assert.Null (Application.MouseGrabView);
-        Assert.Equal (tf1, Application.ViewsUnderMouse.LastOrDefault ());
+        Assert.Equal (tf1, Application._cachedViewsUnderMouse.LastOrDefault ());
 
 
         // Click on tf2 to focus it
         // Click on tf2 to focus it
         Application.OnMouseEvent (new () { Position = new (1, 3), Flags = MouseFlags.Button1Clicked });
         Application.OnMouseEvent (new () { Position = new (1, 3), Flags = MouseFlags.Button1Clicked });
@@ -1428,7 +1428,7 @@ public class ContextMenuTests (ITestOutputHelper output)
         Assert.NotNull (tf2.ContextMenu.MenuBar);
         Assert.NotNull (tf2.ContextMenu.MenuBar);
         Assert.Equal (win.Focused, tf2);
         Assert.Equal (win.Focused, tf2);
         Assert.Null (Application.MouseGrabView);
         Assert.Null (Application.MouseGrabView);
-        Assert.Equal (tf2, Application.ViewsUnderMouse.LastOrDefault ());
+        Assert.Equal (tf2, Application._cachedViewsUnderMouse.LastOrDefault ());
 
 
         Application.End (rs);
         Application.End (rs);
         win.Dispose ();
         win.Dispose ();