diff --git a/Terminal.Gui/Core/ContextMenu.cs b/Terminal.Gui/Core/ContextMenu.cs index aeed58277..75869b2b4 100644 --- a/Terminal.Gui/Core/ContextMenu.cs +++ b/Terminal.Gui/Core/ContextMenu.cs @@ -132,7 +132,7 @@ namespace Terminal.Gui { /// public void Hide () { - menuBar.CloseAllMenus (); + menuBar.CleanUp (); Dispose (); } @@ -196,5 +196,10 @@ namespace Terminal.Gui { /// if the left or right position are negative. /// public bool ForceMinimumPosToZero { get; set; } = true; + + /// + /// Gets the that is hosting this context menu. + /// + public MenuBar MenuBar { get => menuBar; } } } diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 7006c5b0a..b8105dd4e 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -377,7 +377,7 @@ namespace Terminal.Gui { class Menu : View { internal MenuBarItem barItems; - MenuBar host; + internal MenuBar host; internal int current; internal View previousSubFocused; @@ -905,6 +905,11 @@ namespace Terminal.Gui { // The right way to do this is to SetFocus(MenuBar), but for some reason // that faults. + var mbar = GetMouseGrabViewInstance (this); + if (mbar != null) { + mbar.CleanUp (); + } + //Activate (0); //StartMenu (); IsMenuOpen = true; @@ -1173,6 +1178,11 @@ namespace Terminal.Gui { /// public void OpenMenu () { + var mbar = GetMouseGrabViewInstance (this); + if (mbar != null) { + mbar.CleanUp (); + } + if (openMenu != null) return; selected = 0; @@ -1662,6 +1672,8 @@ namespace Terminal.Gui { var menu = new Menu (this, i, 0, Menus [i]); menu.Run (Menus [i].Action); menu.Dispose (); + } else if (!IsMenuOpen) { + Activate (i); } } else if (me.Flags == MouseFlags.Button1Pressed || me.Flags == MouseFlags.Button1DoubleClicked || me.Flags == MouseFlags.Button1TripleClicked) { if (IsMenuOpen && !Menus [i].IsTopLevel) { @@ -1696,6 +1708,16 @@ namespace Terminal.Gui { { if (Application.mouseGrabView != null) { if (me.View is MenuBar || me.View is Menu) { + var mbar = GetMouseGrabViewInstance (me.View); + if (mbar != null) { + if (me.Flags == MouseFlags.Button1Clicked) { + mbar.CleanUp (); + Application.GrabMouse (me.View); + } else { + handled = false; + return false; + } + } if (me.View != current) { Application.UngrabMouse (); var v = me.View; @@ -1791,6 +1813,30 @@ namespace Terminal.Gui { return true; } + MenuBar GetMouseGrabViewInstance (View view) + { + if (view == null || Application.mouseGrabView == null) { + return null; + } + + MenuBar hostView = null; + if (view is MenuBar) { + hostView = (MenuBar)view; + } else if (view is Menu) { + hostView = ((Menu)view).host; + } + + var grabView = Application.mouseGrabView; + MenuBar hostGrabView = null; + if (grabView is MenuBar) { + hostGrabView = (MenuBar)grabView; + } else if (grabView is Menu) { + hostGrabView = ((Menu)grabView).host; + } + + return hostView != hostGrabView ? hostGrabView : null; + } + /// public override bool OnEnter (View view) { diff --git a/UnitTests/ContextMenuTests.cs b/UnitTests/ContextMenuTests.cs index 291b952a6..0610e1f22 100644 --- a/UnitTests/ContextMenuTests.cs +++ b/UnitTests/ContextMenuTests.cs @@ -463,5 +463,57 @@ namespace Terminal.Gui.Core { pos = GraphViewTests.AssertDriverContentsWithPosAre (expected, output); Assert.Equal (new Point (1, 0), pos); } + + [Fact, AutoInitShutdown] + public void ContextMenu_Is_Closed_If_Another_MenuBar_Is_Open_Or_Vice_Versa () + { + var cm = new ContextMenu (10, 5, + new MenuBarItem (new MenuItem [] { + new MenuItem ("One", "", null), + new MenuItem ("Two", "", null) + }) + ); + + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem ("File", "", null), + new MenuBarItem ("Edit", "", null) + }); + + Application.Top.Add (menu); + + Assert.Null (Application.mouseGrabView); + + cm.Show (); + Assert.True (ContextMenu.IsShow); + Assert.Equal (cm.MenuBar, Application.mouseGrabView); + Assert.False (menu.IsMenuOpen); + Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + Assert.False (ContextMenu.IsShow); + Assert.Equal (menu, Application.mouseGrabView); + Assert.True (menu.IsMenuOpen); + + cm.Show (); + Assert.True (ContextMenu.IsShow); + Assert.Equal (cm.MenuBar, Application.mouseGrabView); + Assert.False (menu.IsMenuOpen); + 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.False (ContextMenu.IsShow); + Assert.Equal (menu, Application.mouseGrabView); + Assert.True (menu.IsMenuOpen); + + cm.Show (); + Assert.True (ContextMenu.IsShow); + Assert.Equal (cm.MenuBar, Application.mouseGrabView); + Assert.False (menu.IsMenuOpen); + Assert.False (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.ReportMousePosition, View = menu })); + Assert.True (ContextMenu.IsShow); + Assert.Equal (cm.MenuBar, Application.mouseGrabView); + Assert.False (menu.IsMenuOpen); + Assert.True (menu.MouseEvent (new MouseEvent () { X = 1, Flags = MouseFlags.Button1Clicked, View = menu })); + Assert.False (ContextMenu.IsShow); + Assert.Equal (menu, Application.mouseGrabView); + Assert.True (menu.IsMenuOpen); + } } }