Jelajahi Sumber

Fighting with Menubar/contextMenu which are effing hacks.

Tig 11 bulan lalu
induk
melakukan
f65f26f846

+ 20 - 0
Terminal.Gui/Application/Application.Mouse.cs

@@ -139,6 +139,12 @@ public static partial class Application // Mouse handling
 
         if (view is { })
         {
+#if DEBUG_IDISPOSABLE
+            if (view.WasDisposed)
+            {
+                throw new ObjectDisposedException (view.GetType ().FullName);
+            }
+#endif
             mouseEvent.View = view;
         }
 
@@ -151,6 +157,13 @@ public static partial class Application // Mouse handling
 
         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);
@@ -170,6 +183,13 @@ public static partial class Application // Mouse handling
             }
 
             //System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}");
+
+#if DEBUG_IDISPOSABLE
+            if (MouseGrabView.WasDisposed)
+            {
+                throw new ObjectDisposedException (MouseGrabView.GetType ().FullName);
+            }
+#endif
             if (MouseGrabView?.NewMouseEvent (viewRelativeMouseEvent) == true)
             {
                 return;

+ 0 - 16
Terminal.Gui/View/View.Hierarchy.cs

@@ -73,22 +73,6 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
             {
                 view.SetFocus ();
             }
-
-#if AUTO_CANFOCUS
-            // BUGBUG: This is a poor API design. Automatic behavior like this is non-obvious and should be avoided. Instead, callers to Add should be explicit about what they want.
-            _addingViewSoCanFocusAlsoUpdatesSuperView = true;
-
-            if (SuperView?.CanFocus == false)
-            {
-                SuperView._addingViewSoCanFocusAlsoUpdatesSuperView = true;
-                SuperView.CanFocus = true;
-                SuperView._addingViewSoCanFocusAlsoUpdatesSuperView = false;
-            }
-
-            // QUESTION: This automatic behavior of setting CanFocus to true on the SuperView is not documented, and is annoying.
-            CanFocus = true;
-            _addingViewSoCanFocusAlsoUpdatesSuperView = false;
-#endif
         }
 
         if (view.Enabled && !Enabled)

+ 1 - 1
Terminal.Gui/View/View.Mouse.cs

@@ -244,7 +244,7 @@ public partial class View // Mouse APIs
         if (!Enabled)
         {
             // QUESTION: Is this right? Should a disabled view eat mouse clicks?
-            return args.Handled = true;
+            return args.Handled = false;
         }
 
         MouseClick?.Invoke (this, args);

+ 22 - 3
Terminal.Gui/View/View.Navigation.cs

@@ -41,6 +41,12 @@ public partial class View // Focus and cross-view navigation management (TabStop
     {
         set
         {
+#if DEBUG_IDISPOSABLE
+            if (WasDisposed)
+            {
+                throw new ObjectDisposedException (GetType ().FullName);
+            }
+#endif
             if (HasFocus != value)
             {
                 if (value)
@@ -59,7 +65,16 @@ public partial class View // Focus and cross-view navigation management (TabStop
                 }
             }
         }
-        get => _hasFocus;
+        get
+        {
+#if DEBUG_IDISPOSABLE
+            if (WasDisposed)
+            {
+                throw new ObjectDisposedException (GetType ().FullName);
+            }
+#endif
+            return _hasFocus;
+        }
     }
 
     /// <summary>
@@ -163,6 +178,10 @@ public partial class View // Focus and cross-view navigation management (TabStop
             }
         }
 
+        if (previousFocusedView is { HasFocus: true } && Subviews.Contains (previousFocusedView))
+        {
+            previousFocusedView.SetHasFocusFalse (this, false);
+        }
         NotifyFocusChanged (HasFocus, previousFocusedView, this);
         SetNeedsDisplay ();
 
@@ -258,7 +277,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
                 return;
             }
 
-            if (Application.Navigation is { })
+            if (Application.Navigation is { } && Application.Current is {})
             {
                 // Temporarily ensure this view can't get focus
                 bool prevCanFocus = _canFocus;
@@ -313,7 +332,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
         // Post-conditions - prove correctness
         if (HasFocus == previousValue)
         {
-            throw new InvalidOperationException ($"LeaveFocus and the HasFocus value did not change.");
+            throw new InvalidOperationException ($"SetHasFocusFalse and the HasFocus value did not change.");
         }
 
         SetNeedsDisplay ();

+ 17 - 4
Terminal.Gui/Views/Menu/ContextMenu.cs

@@ -121,10 +121,19 @@ public sealed class ContextMenu : IDisposable
     }
 
     /// <summary>Hides (closes) the ContextMenu.</summary>
-    public void Hide ()
+    public void Hide (bool dispose = false)
     {
-        _menuBar?.CleanUp ();
-        Dispose ();
+        if (_menuBar is { })
+        {
+            //_menuBar?.CleanUp ();
+            _menuBar.Enabled = false;
+
+            if (dispose)
+            {
+                _menuBar.Dispose ();
+                _menuBar = null;
+            }
+        }
     }
 
     /// <summary>Event invoked when the <see cref="ContextMenu.Key"/> is changed.</summary>
@@ -221,5 +230,9 @@ public sealed class ContextMenu : IDisposable
 
     private void Container_Deactivate (object sender, ToplevelEventArgs e) { Hide (); }
     private void Container_Closing (object sender, ToplevelClosingEventArgs obj) { Hide (); }
-    private void MenuBar_MenuAllClosed (object sender, EventArgs e) { Dispose (); }
+
+    private void MenuBar_MenuAllClosed (object sender, EventArgs e)
+    {
+        Hide (true);
+    }
 }

+ 4 - 1
Terminal.Gui/Views/Menu/Menu.cs

@@ -589,7 +589,10 @@ internal sealed class Menu : View
 
     protected override void OnHasFocusChanged (bool newHasFocus, View previousFocusedView, View view)
     {
-        _host.LostFocus (view);
+        if (!newHasFocus)
+        {
+            _host.LostFocus (previousFocusedView);
+        }
     }
 
     private void RunSelected ()

+ 76 - 41
Terminal.Gui/Views/Menu/MenuBar.cs

@@ -115,9 +115,6 @@ public class MenuBar : View, IDesignable
     /// <summary><see langword="true"/> if the menu is open; otherwise <see langword="true"/>.</summary>
     public bool IsMenuOpen { get; protected set; }
 
-    /// <summary>Gets the view that was last focused before opening the menu.</summary>
-    public View LastFocused { get; private set; }
-
     /// <summary>
     ///     Gets or sets the array of <see cref="MenuBarItem"/>s for the menu. Only set this after the
     ///     <see cref="MenuBar"/> is visible.
@@ -355,7 +352,7 @@ public class MenuBar : View, IDesignable
 
         _selected = 0;
 
-        _previousFocused = null;//SuperView is null ? Application.Current?.Focused : SuperView.Focused;
+        _previousFocused = Application.Navigation?.GetFocused ();
         OpenMenu (_selected);
 
         if (!SelectEnabledItem (
@@ -418,7 +415,7 @@ public class MenuBar : View, IDesignable
 
         if (_openMenu is null)
         {
-            _previousFocused = null;//SuperView is null ? Application.Current?.Focused ?? null : SuperView.Focused;
+            _previousFocused = Application.Navigation?.GetFocused ();
         }
 
         return OpenMenu (idx, sIdx, subMenu);
@@ -461,16 +458,23 @@ public class MenuBar : View, IDesignable
                 return;
             }
 
-            if (LastFocused is { } && LastFocused != this)
+#if DEBUG_IDISPOSABLE
+            if (WasDisposed)
             {
-                _selected = -1;
+                throw new ObjectDisposedException (GetType ().FullName);
             }
+#endif
+
+            _selected = -1;
+            Enabled = false;
 
             Application.UngrabMouse ();
         }
 
-        if (OpenCurrentMenu is { })
+        if (OpenCurrentMenu is { } && OpenCurrentMenu is Menu)
         {
+            OpenCurrentMenu.HasFocus = false;
+            OpenCurrentMenu.Dispose ();
             OpenCurrentMenu = null;
         }
 
@@ -513,52 +517,35 @@ public class MenuBar : View, IDesignable
                     Application.Current?.Remove (_openMenu);
                 }
 
-                if (_previousFocused is Menu && _openMenu is { } && _previousFocused.ToString () != OpenCurrentMenu.ToString ())
+                if (_previousFocused is Menu && _openMenu is { } && (OpenCurrentMenu is {} && _previousFocused.ToString () != OpenCurrentMenu.ToString ()))
                 {
                     _previousFocused.SetFocus ();
                 }
 
                 _openMenu?.Dispose ();
-                _openMenu = null;
-
-                if (_lastFocused is Menu or MenuBar)
+                if (_openMenu == OpenCurrentMenu)
                 {
-                    _lastFocused = null;
+                    OpenCurrentMenu = null;
                 }
+                _openMenu = null;
 
-                LastFocused = _lastFocused;
-                _lastFocused = null;
-
-                if (LastFocused is { CanFocus: true })
-                {
-                    if (!reopen)
-                    {
-                        _selected = -1;
-                    }
-
-                    if (_openSubMenu is { })
-                    {
-                        _openSubMenu = null;
-                    }
-
-                    if (OpenCurrentMenu is { })
-                    {
-                        Application.Current?.Remove (OpenCurrentMenu);
-                        OpenCurrentMenu.Dispose ();
-                        OpenCurrentMenu = null;
-                    }
-
-                    LastFocused.SetFocus ();
-                }
-                else if (_openSubMenu is null || _openSubMenu.Count == 0)
+                if (_openSubMenu is null || _openSubMenu.Count == 0)
                 {
                     CloseAllMenus ();
+
+                    return false;
                 }
                 else
                 {
                     SetFocus ();
                 }
 
+#if DEBUG_IDISPOSABLE
+                if (WasDisposed)
+                {
+                    throw new ObjectDisposedException (GetType ().FullName);
+                }
+#endif
                 IsMenuOpen = false;
                 break;
 
@@ -575,6 +562,12 @@ public class MenuBar : View, IDesignable
         _reopen = false;
         _isMenuClosing = false;
 
+#if DEBUG_IDISPOSABLE
+        if (WasDisposed)
+        {
+            throw new ObjectDisposedException (GetType ().FullName);
+        }
+#endif
         return true;
     }
 
@@ -726,6 +719,11 @@ public class MenuBar : View, IDesignable
                 {
                     Application.Current?.Remove (_openMenu);
                     _openMenu.Dispose ();
+
+                    if (_openMenu == OpenCurrentMenu)
+                    {
+                        OpenCurrentMenu = null;
+                    }
                     _openMenu = null;
                 }
 
@@ -916,6 +914,11 @@ public class MenuBar : View, IDesignable
             foreach (Menu item in _openSubMenu)
             {
                 Application.Current.Remove (item);
+
+                if (item == OpenCurrentMenu)
+                {
+                    OpenCurrentMenu = null;
+                }
                 item.Dispose ();
             }
         }
@@ -1037,7 +1040,6 @@ public class MenuBar : View, IDesignable
         if (_openedByAltKey)
         {
             _openedByAltKey = false;
-            LastFocused?.SetFocus ();
         }
 
         return true;
@@ -1099,6 +1101,11 @@ public class MenuBar : View, IDesignable
             Point screen = ViewportToScreen (new Point (0, i));
             var menu = new Menu { Host = this, X = screen.X, Y = screen.Y, BarItems = mi };
             menu.Run (mi.Action);
+
+            if (menu == OpenCurrentMenu)
+            {
+                OpenCurrentMenu = null;
+            }
             menu.Dispose ();
         }
         else
@@ -1171,6 +1178,10 @@ public class MenuBar : View, IDesignable
                 }
 
                 menu.Dispose ();
+                if (menu == OpenCurrentMenu)
+                {
+                    OpenCurrentMenu = null;
+                }
             }
 
             RemoveSubMenu (i, ignoreUseSubMenusSingleFrame);
@@ -1303,7 +1314,7 @@ public class MenuBar : View, IDesignable
     /// <inheritdoc/>
     internal void LostFocus (View view)
     {
-        if (((!(view is MenuBar) && !(view is Menu)) || (!(view is MenuBar) && !(view is Menu) && _openMenu is { })) && !_isCleaning && !_reopen)
+        if (((!(view is MenuBar) && !(view is Menu))) && !_isCleaning && !_reopen)
         {
             CleanUp ();
         }
@@ -1314,11 +1325,22 @@ public class MenuBar : View, IDesignable
     /// <inheritdoc/>
     protected internal override bool OnMouseEvent (MouseEvent me)
     {
-        if (!_handled && !HandleGrabView (me, this))
+        if (!HandleGrabView (me, this))
+        {
+            return false;
+        }
+
+        if (!IsMenuOpen)
+        {
+            return false;
+        }
+
+        if (!_handled)
         {
             return false;
         }
 
+
         _handled = false;
 
         if (me.Flags == MouseFlags.Button1Pressed
@@ -1351,6 +1373,10 @@ public class MenuBar : View, IDesignable
                             var menu = new Menu { Host = this, X = screen.X, Y = screen.Y, BarItems = Menus [i] };
                             menu.Run (Menus [i].Action);
                             menu.Dispose ();
+                            if (menu == OpenCurrentMenu)
+                            {
+                                OpenCurrentMenu = null;
+                            }
                         }
                         else if (!IsMenuOpen)
                         {
@@ -1487,9 +1513,18 @@ public class MenuBar : View, IDesignable
                     CloseAllMenus ();
                 }
 
+//#if DEBUG_IDISPOSABLE
+//                if (WasDisposed)
+//                {
+//                    throw new ObjectDisposedException (GetType ().FullName);
+//                }
+//#endif
                 _handled = false;
 
+                Enabled = false;
                 return false;
+
+
             }
             else
             {

+ 17 - 17
UnitTests/Views/MenuBarTests.cs

@@ -3064,7 +3064,7 @@ Edit
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 0, 10, 6), pos);
 
-        Assert.False (
+        Assert.True (
                       menu.NewMouseEvent (
                                           new () { Position = new (70, 2), Flags = MouseFlags.Button1Clicked, View = Application.Top }
                                          )
@@ -3329,7 +3329,7 @@ Edit
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 0, 10, 6), pos);
 
-        Assert.False (menu.NewMouseEvent (new () { Position = new (1, 2), Flags = MouseFlags.Button1Clicked, View = Application.Top.Subviews [1] }));
+        Assert.True (menu.NewMouseEvent (new () { Position = new (1, 2), Flags = MouseFlags.Button1Clicked, View = Application.Top.Subviews [1] }));
         top.Draw ();
 
         expected = @"
@@ -3345,7 +3345,7 @@ Edit
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 0, 15, 7), pos);
 
-        Assert.False (menu.NewMouseEvent (new () { Position = new (1, 1), Flags = MouseFlags.Button1Clicked, View = Application.Top.Subviews [2] }));
+        Assert.True (menu.NewMouseEvent (new () { Position = new (1, 1), Flags = MouseFlags.Button1Clicked, View = Application.Top.Subviews [2] }));
         top.Draw ();
 
         expected = @"
@@ -3514,11 +3514,11 @@ Edit
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 0, 8, 4), pos);
 
-        Assert.False (
-                      menu.NewMouseEvent (
-                                          new () { Position = new (1, 2), Flags = MouseFlags.Button1Clicked, View = Application.Top.Subviews [1] }
-                                         )
-                     );
+        Assert.True (
+                     menu.NewMouseEvent (
+                                         new () { Position = new (1, 2), Flags = MouseFlags.Button1Clicked, View = Application.Top.Subviews [1] }
+                                        )
+                    );
         top.Draw ();
 
         expected = @"
@@ -3532,11 +3532,11 @@ Edit
         pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output);
         Assert.Equal (new (1, 0, 13, 5), pos);
 
-        Assert.False (
-                      menu.NewMouseEvent (
-                                          new () { Position = new (1, 1), Flags = MouseFlags.Button1Clicked, View = Application.Top.Subviews [2] }
-                                         )
-                     );
+        Assert.True (
+                     menu.NewMouseEvent (
+                                         new () { Position = new (1, 1), Flags = MouseFlags.Button1Clicked, View = Application.Top.Subviews [2] }
+                                        )
+                    );
         top.Draw ();
 
         expected = @"
@@ -3550,10 +3550,10 @@ Edit
         Assert.Equal (new (1, 0, 8, 4), pos);
 
         Assert.False (
-                      menu.NewMouseEvent (
-                                          new () { Position = new (70, 2), Flags = MouseFlags.Button1Clicked, View = Application.Top }
-                                         )
-                     );
+                     menu.NewMouseEvent (
+                                         new () { Position = new (70, 2), Flags = MouseFlags.Button1Clicked, View = Application.Top }
+                                        )
+                    );
         top.Draw ();
 
         expected = @"