Sfoglia il codice sorgente

Fixes #4129 - `GetViewsUnderMouse` does not return anything (#4130)

Tig 3 mesi fa
parent
commit
23cc44ca48

+ 20 - 1
Terminal.Gui/App/IPopover.cs

@@ -26,7 +26,26 @@ namespace Terminal.Gui.App;
 ///         </list>
 ///     </para>
 ///     <para>
-///         To implement a custom popover, inherit from <see cref="PopoverBaseImpl"/> or implement this interface directly.
+///         <b>Focus and Input:</b><br/>
+///         When visible, a popover receives focus and input events. If the user clicks outside the popover (and not on a
+///         subview),
+///         presses <see cref="Application.QuitKey"/>, or another popover is shown, the popover will be hidden
+///         automatically.
+///     </para>
+///     <para>
+///         <b>Layout:</b><br/>
+///         When the popover becomes visible, it is automatically laid out to fill the screen by default. You can override
+///         this behavior
+///         by setting <see cref="View.Width"/> and <see cref="View.Height"/> in your derived class.
+///     </para>
+///     <para>
+///         <b>Mouse:</b><br/>
+///         Popovers are transparent to mouse events (see <see cref="ViewportSettingsFlags.TransparentMouse"/>),
+///         meaning mouse events in a popover that are not also within a subview of the popover will not be captured.
+///     </para>
+///     <para>
+///         <b>Custom Popovers:</b><br/>
+///         To create a custom popover, inherit from <see cref="PopoverBaseImpl"/> and add your own content and logic.
 ///     </para>
 /// </remarks>
 public interface IPopover

+ 5 - 0
Terminal.Gui/App/PopoverBaseImpl.cs

@@ -26,6 +26,11 @@ namespace Terminal.Gui.App;
 ///         by setting <see cref="View.Width"/> and <see cref="View.Height"/> in your derived class.
 ///     </para>
 ///     <para>
+///         <b>Mouse:</b><br/>
+///         Popovers are transparent to mouse events (see <see cref="ViewportSettingsFlags.TransparentMouse"/>),
+///         meaning mouse events in a popover that are not also within a subview of the popover will not be captured.
+///     </para>
+///     <para>
 ///         <b>Custom Popovers:</b><br/>
 ///         To create a custom popover, inherit from <see cref="PopoverBaseImpl"/> and add your own content and logic.
 ///     </para>

+ 1 - 1
Terminal.Gui/ViewBase/View.Layout.cs

@@ -1166,7 +1166,7 @@ public partial class View // Layout APIs
 
             result.AddRange (GetViewsUnderLocation (visiblePopover, screenLocation, excludeViewportSettingsFlags));
 
-            if (result.Count > 1)
+            if (result.Count > 0)
             {
                 return result;
             }

+ 2 - 4
Terminal.Gui/ViewBase/ViewportSettingsFlags.cs

@@ -153,11 +153,9 @@ public enum ViewportSettingsFlags
     /// </summary>
     Transparent = 0b_0001_0000_0000,
 
-    // BUGBUG: The API docs here are wrong: If a TransparentMouse View has subviews, those subviews WILL get mouse events. 
-    // BUGBUG: That's an important feature that enables Popovers to work.
     /// <summary>
-    ///     If set the View will be transparent to mouse events: Any mouse event that occurs over the View (and it's SubViews) will be passed to the
-    ///     Views below it.
+    ///     If set the View will be transparent to mouse events: Specifically, any mouse event that occurs over the View that is NOT occupied by a SubView
+    ///     will not be captured by the View.
     ///     <para>
     ///         Combine this with <see cref="Transparent"/> to get a view that is both visually transparent and transparent to the mouse.
     ///     </para>

+ 65 - 3
Tests/UnitTests/Application/ApplicationPopoverTests.cs

@@ -2,9 +2,6 @@
 
 public class ApplicationPopoverTests
 {
-
-
-
     [Fact]
     public void Application_Init_Initializes_PopoverManager ()
     {
@@ -203,6 +200,71 @@ public class ApplicationPopoverTests
         Application.ResetState (true);
     }
 
+    // See: https://github.com/gui-cs/Terminal.Gui/issues/4122
+    [Theory]
+    [InlineData (0, 0, new [] { "top" })]
+    [InlineData (10, 10, new string [] { })]
+    [InlineData (1, 1, new [] { "top", "view" })]
+    [InlineData (5, 5, new [] { "top" })]
+    [InlineData (6, 6, new [] { "popoverSubView" })]
+    [InlineData (7, 7, new [] { "top" })]
+    [InlineData (3, 3, new [] { "top" })]
+    public void GetViewsUnderMouse_Supports_ActivePopover (int mouseX, int mouseY, string [] viewIdStrings)
+    {
+        Application.ResetState (true);
+        // Arrange
+        Assert.Null (Application.Popover);
+        Application.Init (new FakeDriver ());
+        Application.Top = new ()
+        {
+            Frame = new (0, 0, 10, 10),
+            Id = "top"
+        };
+
+        View view = new ()
+        {
+            Id = "view",
+            X = 1,
+            Y = 1,
+            Width = 2,
+            Height = 2,
+        }; // at 1,1 to 3,2 (screen)
+
+        Application.Top.Add (view);
+
+        PopoverTestClass popover = new ()
+        {
+            Id = "popover",
+            X = 5,
+            Y = 5,
+            Width = 3,
+            Height = 3,
+        }; // at 5,5 to 8,8 (screen)
+
+        View popoverSubView = new ()
+        {
+            Id = "popoverSubView",
+            X = 1,
+            Y = 1,
+            Width = 1,
+            Height = 1,
+        }; // at 6,6 to 7,7 (screen)
+
+        popover.Add (popoverSubView);
+
+        Application.Popover?.Show (popover);
+
+        List<View?> found = View.GetViewsUnderLocation (new (mouseX, mouseY), ViewportSettingsFlags.TransparentMouse);
+
+        string [] foundIds = found.Select (v => v!.Id).ToArray ();
+
+        Assert.Equal (viewIdStrings, foundIds);
+
+        popover.Dispose ();
+        Application.Top.Dispose ();
+        Application.ResetState (true);
+    }
+
     public class PopoverTestClass : PopoverBaseImpl
     {
         public List<Key> HandledKeys { get; } = [];