diff --git a/Terminal.Gui/Views/ColorPicker.cs b/Terminal.Gui/Views/ColorPicker.cs index dff7d81336..00d6ee3f5d 100644 --- a/Terminal.Gui/Views/ColorPicker.cs +++ b/Terminal.Gui/Views/ColorPicker.cs @@ -361,7 +361,7 @@ private void UpdateValueFromTextField () } } - + /// protected override void Dispose (bool disposing) { DisposeOldViews (); diff --git a/Terminal.Gui/Views/Menu/ContextMenu.cs b/Terminal.Gui/Views/Menu/ContextMenu.cs index 0ceec6d747..8751ada923 100644 --- a/Terminal.Gui/Views/Menu/ContextMenu.cs +++ b/Terminal.Gui/Views/Menu/ContextMenu.cs @@ -58,7 +58,7 @@ public ContextMenu () public static bool IsShow { get; private set; } /// Specifies the key that will activate the context menu. - public new Key Key + public Key Key { get => _key; set @@ -133,7 +133,7 @@ private void RemoveKeyBindings (MenuBarItem? menuBarItem) return; } - foreach (var menuItem in menuBarItem.Children!) + foreach (MenuItem? menuItem in menuBarItem.Children!) { // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (menuItem is null) @@ -150,7 +150,7 @@ private void RemoveKeyBindings (MenuBarItem? menuBarItem) if (menuItem.ShortcutKey != Key.Empty) { // Remove an existent ShortcutKey - _menuBar?.KeyBindings.Remove (menuItem.ShortcutKey); + _menuBar?.KeyBindings.Remove (menuItem.ShortcutKey!); } } } @@ -171,7 +171,7 @@ public void Show (MenuBarItem? menuItems) Dispose (); } - if (menuItems is null || menuItems.Children.Length == 0) + if (menuItems is null || menuItems.Children!.Length == 0) { return; } diff --git a/Terminal.Gui/Views/Menu/Menu.cs b/Terminal.Gui/Views/Menu/Menu.cs index 5bb2243997..9fcf3fd4c0 100644 --- a/Terminal.Gui/Views/Menu/Menu.cs +++ b/Terminal.Gui/Views/Menu/Menu.cs @@ -13,7 +13,7 @@ internal sealed class Menu : View internal int _currentChild; internal View? _previousSubFocused; - internal static Rectangle MakeFrame (int x, int y, MenuItem []? items, Menu? parent = null) + internal static Rectangle MakeFrame (int x, int y, MenuItem? []? items, Menu? parent = null) { if (items is null || items.Length == 0) { diff --git a/Terminal.Gui/Views/Menu/MenuBar.cs b/Terminal.Gui/Views/Menu/MenuBar.cs index 1415c2d767..76c00ed197 100644 --- a/Terminal.Gui/Views/Menu/MenuBar.cs +++ b/Terminal.Gui/Views/Menu/MenuBar.cs @@ -126,7 +126,12 @@ public MenuBar () return true; } ); - AddCommand (Command.ToggleExpandCollapse, ctx => Select (Menus.IndexOf (ctx.KeyBinding?.Context))); + AddCommand (Command.ToggleExpandCollapse, ctx => + { + CloseOtherOpenedMenuBar (); + + return Select (Menus.IndexOf (ctx.KeyBinding?.Context)); + }); AddCommand (Command.Select, ctx => { var res = Run ((ctx.KeyBinding?.Context as MenuItem)?.Action!); @@ -387,6 +392,8 @@ public void OpenMenu () mbar?.CleanUp (); + CloseOtherOpenedMenuBar (); + if (!Enabled || _openMenu is { }) { return; @@ -528,11 +535,16 @@ internal void CloseAllMenus () _openedByAltKey = false; OnMenuAllClosed (); + CloseOtherOpenedMenuBar (); + } + + private void CloseOtherOpenedMenuBar () + { if (Application.Current is { }) { // Close others menu bar opened - View? cm = Application.Current.Subviews.FirstOrDefault (v => v is Menu cm && cm.Host != this && cm.Host.IsMenuOpen); - (cm as Menu)?.Host.CleanUp (); + Menu? menu = Application.Current.Subviews.FirstOrDefault (v => v is Menu m && m.Host != this && m.Host.IsMenuOpen) as Menu; + menu?.Host.CleanUp (); } } @@ -726,7 +738,7 @@ out OpenCurrentMenu._currentChild else if (subMenu != null || (OpenCurrentMenu._currentChild > -1 && !OpenCurrentMenu.BarItems! - .Children! [OpenCurrentMenu._currentChild] + .Children! [OpenCurrentMenu._currentChild]! .IsFromSubMenu)) { _selectedSub++; @@ -999,7 +1011,7 @@ internal bool Run (Action? action) } internal bool SelectEnabledItem ( - IEnumerable? children, + MenuItem? []? children, int current, out int newCurrent, bool forward = true @@ -1012,11 +1024,11 @@ internal bool SelectEnabledItem ( return true; } - IEnumerable childMenuItems = forward ? children : children.Reverse (); + IEnumerable childMenuItems = forward ? children : children.Reverse (); int count; - IEnumerable menuItems = childMenuItems as MenuItem [] ?? childMenuItems.ToArray (); + IEnumerable menuItems = childMenuItems as MenuItem [] ?? childMenuItems.ToArray (); if (forward) { @@ -1027,7 +1039,7 @@ internal bool SelectEnabledItem ( count = menuItems.Count (); } - foreach (MenuItem child in menuItems) + foreach (MenuItem? child in menuItems) { if (forward) { diff --git a/Terminal.Gui/Views/Menu/MenuItem.cs b/Terminal.Gui/Views/Menu/MenuItem.cs index b99f5f83cb..0c920da529 100644 --- a/Terminal.Gui/Views/Menu/MenuItem.cs +++ b/Terminal.Gui/Views/Menu/MenuItem.cs @@ -351,10 +351,10 @@ public virtual void RemoveMenuItem () { if (Parent is { }) { - MenuItem []? childrens = ((MenuBarItem)Parent).Children; + MenuItem? []? childrens = ((MenuBarItem)Parent).Children; var i = 0; - foreach (MenuItem c in childrens!) + foreach (MenuItem? c in childrens!) { if (c != this) { diff --git a/UICatalog/Scenarios/ContextMenus.cs b/UICatalog/Scenarios/ContextMenus.cs index 477fa11988..01c4e340e6 100644 --- a/UICatalog/Scenarios/ContextMenus.cs +++ b/UICatalog/Scenarios/ContextMenus.cs @@ -98,8 +98,8 @@ public override void Main () Menus = [ new ( - "File", - new MenuItem [] { new ("Quit", "", () => Application.RequestStop (), null, null, Application.QuitKey) }) + "_File", + new MenuItem [] { new ("_Quit", "", () => Application.RequestStop (), null, null, Application.QuitKey) }) ] }; @@ -170,6 +170,10 @@ private void ShowContextMenu (int x, int y) MenuBarItem menuItems = new ( new [] { + new MenuBarItem ( + "_Languages", + GetSupportedCultures () + ), new ( "_Configuration", "Show configuration", @@ -214,10 +218,6 @@ private void ShowContextMenu (int x, int y) ) } ), - new MenuBarItem ( - "_Languages", - GetSupportedCultures () - ), _miForceMinimumPosToZero = new ( "Fo_rceMinimumPosToZero", diff --git a/UICatalog/Scenarios/DynamicMenuBar.cs b/UICatalog/Scenarios/DynamicMenuBar.cs index ad00a9a691..2cfbe93a4f 100644 --- a/UICatalog/Scenarios/DynamicMenuBar.cs +++ b/UICatalog/Scenarios/DynamicMenuBar.cs @@ -875,7 +875,7 @@ public DynamicMenuBarSample () { MenuItem newMenu = CreateNewMenu (item, _currentMenuBarItem); var menuBarItem = _currentMenuBarItem as MenuBarItem; - menuBarItem.AddMenuBarItem (newMenu); + menuBarItem.AddMenuBarItem (MenuBar, newMenu); DataContext.Menus.Add (new () { Title = newMenu.Title, MenuItem = newMenu }); @@ -915,6 +915,11 @@ public DynamicMenuBarSample () _lstMenus.SelectedItem = _lstMenus.Source.Count - 1; } + if (_menuBar.Menus.Length == 0) + { + RemoveMenuBar (); + } + _lstMenus.SetNeedsDisplay (); SetFrameDetails (); } @@ -992,7 +997,7 @@ public DynamicMenuBarSample () } var newMenu = CreateNewMenu (item) as MenuBarItem; - newMenu.AddMenuBarItem (); + newMenu.AddMenuBarItem (MenuBar); _currentMenuBarItem = newMenu; _currentMenuBarItem.CheckType = item.CheckStyle; @@ -1012,7 +1017,7 @@ public DynamicMenuBarSample () btnRemoveMenuBar.Accept += (s, e) => { - if (_menuBar == null || _menuBar.Menus.Length == 0) + if (_menuBar == null) { return; } @@ -1033,25 +1038,30 @@ public DynamicMenuBarSample () : null; } - if (MenuBar != null && _currentMenuBarItem == null && _menuBar.Menus.Length == 0) - { - Remove (_menuBar); - _menuBar.Dispose (); - _menuBar = null; - DataContext.Menus = new (); - _currentMenuBarItem = null; - _currentSelectedMenuBar = -1; - lblMenuBar.Text = string.Empty; - } - else - { - lblMenuBar.Text = _menuBar.Menus [_currentSelectedMenuBar].Title; - } + RemoveMenuBar (); SetListViewSource (_currentMenuBarItem, true); SetFrameDetails (); }; + void RemoveMenuBar () + { + if (MenuBar != null && _currentMenuBarItem == null && _menuBar.Menus.Length == 0) + { + Remove (_menuBar); + _menuBar.Dispose (); + _menuBar = null; + DataContext.Menus = new (); + _currentMenuBarItem = null; + _currentSelectedMenuBar = -1; + lblMenuBar.Text = string.Empty; + } + else + { + lblMenuBar.Text = _menuBar.Menus [_currentSelectedMenuBar].Title; + } + } + SetFrameDetails (); var ustringConverter = new UStringValueConverter (); diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index 6723d9876b..471e0984ad 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -875,7 +875,7 @@ string GetDiagnosticsTitle (Enum diag) }; } - Enum GetDiagnosticsEnumValue (string title) + Enum GetDiagnosticsEnumValue (string? title) { return title switch { diff --git a/UnitTests/Views/ContextMenuTests.cs b/UnitTests/Views/ContextMenuTests.cs index e31170b3c8..0872e2de9a 100644 --- a/UnitTests/Views/ContextMenuTests.cs +++ b/UnitTests/Views/ContextMenuTests.cs @@ -19,10 +19,10 @@ public void ContextMenu_Constructors () cm.Position = new Point (20, 10); var menuItems = new MenuBarItem ( - [ - new MenuItem ("First", "", null) - ] - ); + [ + new MenuItem ("First", "", null) + ] + ); cm.Show (menuItems); Assert.Equal (new Point (20, 10), cm.Position); Assert.Single (cm.MenuItems!.Children); @@ -42,6 +42,7 @@ public void ContextMenu_Constructors () var view = new View { X = 5, Y = 10 }; top.Add (view); + cm = new ContextMenu { Host = view, @@ -74,6 +75,7 @@ public void ContextMenu_Is_Closed_If_Another_MenuBar_Is_Open_Or_Vice_Versa () new MenuItem ("Two", "", null) ] ); + var menu = new MenuBar { Menus = @@ -401,6 +403,7 @@ public void Key_Open_And_Close_The_ContextMenu () Assert.True (Application.OnKeyDown (ContextMenu.DefaultKey)); Assert.True (tf.ContextMenu.MenuBar!.IsMenuOpen); Assert.True (Application.OnKeyDown (ContextMenu.DefaultKey)); + // The last context menu bar opened is always preserved Assert.NotNull (tf.ContextMenu.MenuBar); top.Dispose (); @@ -529,8 +532,8 @@ public void Menus_And_SubMenus_Always_Try_To_Be_On_Screen () Assert.True ( top.Subviews [0] .NewMouseEvent ( - new MouseEvent { Position = new (0, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } - ) + new MouseEvent { Position = new (0, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } + ) ); Application.Refresh (); Assert.Equal (new Point (-1, -2), cm.Position); @@ -577,8 +580,8 @@ top.Subviews [0] Assert.True ( top.Subviews [0] .NewMouseEvent ( - new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } - ) + new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } + ) ); Application.Refresh (); Assert.Equal (new Point (41, -2), cm.Position); @@ -624,8 +627,8 @@ top.Subviews [0] Assert.True ( top.Subviews [0] .NewMouseEvent ( - new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } - ) + new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } + ) ); Application.Refresh (); Assert.Equal (new Point (41, 9), cm.Position); @@ -668,8 +671,8 @@ top.Subviews [0] Assert.True ( top.Subviews [0] .NewMouseEvent ( - new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } - ) + new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } + ) ); Application.Refresh (); Assert.Equal (new Point (41, 22), cm.Position); @@ -712,8 +715,8 @@ top.Subviews [0] Assert.True ( top.Subviews [0] .NewMouseEvent ( - new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } - ) + new MouseEvent { Position = new (30, 3), Flags = MouseFlags.ReportMousePosition, View = top.Subviews [0] } + ) ); Application.Refresh (); Assert.Equal (new Point (19, 10), cm.Position); @@ -1408,6 +1411,7 @@ public void Handling_TextField_With_Opened_ContextMenu_By_Mouse_HasFocus () Assert.True (tf1.HasFocus); Assert.False (tf2.HasFocus); Assert.Equal (4, win.Subviews.Count); + // The last context menu bar opened is always preserved Assert.NotNull (tf2.ContextMenu.MenuBar); Assert.Equal (win.Focused, tf1); @@ -1419,6 +1423,7 @@ public void Handling_TextField_With_Opened_ContextMenu_By_Mouse_HasFocus () Assert.False (tf1.HasFocus); Assert.True (tf2.HasFocus); Assert.Equal (4, win.Subviews.Count); + // The last context menu bar opened is always preserved Assert.NotNull (tf2.ContextMenu.MenuBar); Assert.Equal (win.Focused, tf2); @@ -1447,7 +1452,7 @@ public void Empty_Menus_Items_Children_Does_Not_Open_The_Menu () [Fact] [AutoInitShutdown] - public void KeyBinding_Removed_On_Close_ContextMenu () + public void KeyBindings_Removed_On_Close_ContextMenu () { var newFile = false; var renameFile = false; @@ -1539,7 +1544,7 @@ public void KeyBindings_With_ContextMenu_And_MenuBar () var menuItems = new MenuBarItem ( [ - new MenuItem ("Rename File", string.Empty, Rename, null, null, Key.R.WithCtrl), + new ("Rename File", string.Empty, Rename, null, null, Key.R.WithCtrl), ] ); var top = new Toplevel (); @@ -1618,7 +1623,7 @@ public void KeyBindings_With_Same_Shortcut_ContextMenu_And_MenuBar () var menuItems = new MenuBarItem ( [ - new MenuItem ("New File", string.Empty, NewContextMenu, null, null, Key.N.WithCtrl), + new ("New File", string.Empty, NewContextMenu, null, null, Key.N.WithCtrl), ] ); var top = new Toplevel (); @@ -1643,6 +1648,7 @@ public void KeyBindings_With_Same_Shortcut_ContextMenu_And_MenuBar () Assert.True (Application.OnKeyDown (Key.N.WithCtrl)); Application.MainLoop!.RunIteration (); Assert.False (newMenuBar); + // The most focused shortcut is executed Assert.True (newContextMenu); Assert.False (cm.MenuBar!.IsMenuOpen); @@ -1663,4 +1669,269 @@ public void KeyBindings_With_Same_Shortcut_ContextMenu_And_MenuBar () void NewContextMenu () { newContextMenu = true; } } -} + + [Fact] + [AutoInitShutdown] + public void HotKeys_Removed_On_Close_ContextMenu () + { + var newFile = false; + var renameFile = false; + var deleteFile = false; + + var cm = new ContextMenu (); + + var menuItems = new MenuBarItem ( + [ + new ("_New File", string.Empty, New, null, null), + new ("_Rename File", string.Empty, Rename, null, null), + new ("_Delete File", string.Empty, Delete, null, null) + ] + ); + var top = new Toplevel (); + Application.Begin (top); + + Assert.Null (cm.MenuBar); + Assert.False (Application.OnKeyDown (Key.N.WithAlt)); + Assert.False (Application.OnKeyDown (Key.R.WithAlt)); + Assert.False (Application.OnKeyDown (Key.D.WithAlt)); + Assert.False (newFile); + Assert.False (renameFile); + Assert.False (deleteFile); + + cm.Show (menuItems); + Assert.True (cm.MenuBar!.IsMenuOpen); + Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt)); + Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.NoShift)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.WithAlt)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.NoShift)); + Assert.Single (Application.Current!.Subviews); + View [] menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == cm.MenuBar).ToArray (); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.N.WithAlt)); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.N.NoShift)); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.D.WithAlt)); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.D.NoShift)); + + Assert.True (Application.OnKeyDown (Key.N.WithAlt)); + Assert.False (cm.MenuBar!.IsMenuOpen); + Application.MainLoop!.RunIteration (); + Assert.True (newFile); + cm.Show (menuItems); + Assert.True (Application.OnKeyDown (Key.R.WithAlt)); + Assert.False (cm.MenuBar.IsMenuOpen); + Application.MainLoop!.RunIteration (); + Assert.True (renameFile); + cm.Show (menuItems); + Assert.True (Application.OnKeyDown (Key.D.WithAlt)); + Assert.False (cm.MenuBar.IsMenuOpen); + Application.MainLoop!.RunIteration (); + Assert.True (deleteFile); + + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.N.NoShift)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.WithAlt)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.D.NoShift)); + + newFile = false; + renameFile = false; + deleteFile = false; + Assert.False (Application.OnKeyDown (Key.N.WithAlt)); + Assert.False (Application.OnKeyDown (Key.R.WithAlt)); + Assert.False (Application.OnKeyDown (Key.D.WithAlt)); + Assert.False (newFile); + Assert.False (renameFile); + Assert.False (deleteFile); + + top.Dispose (); + + void New () { newFile = true; } + + void Rename () { renameFile = true; } + + void Delete () { deleteFile = true; } + } + + [Fact] + [AutoInitShutdown] + public void HotKeys_With_ContextMenu_And_MenuBar () + { + var newFile = false; + var renameFile = false; + + var menuBar = new MenuBar + { + Menus = + [ + new ( + "_File", + new MenuItem [] + { + new ("_New", string.Empty, New) + }) + ] + }; + var cm = new ContextMenu (); + + var menuItems = new MenuBarItem ( + [ + new MenuBarItem ( + "_Edit", + new MenuItem [] + { + new ("_Rename File", string.Empty, Rename) + } + ) + ] + ); + var top = new Toplevel (); + top.Add (menuBar); + Application.Begin (top); + + Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.WithAlt)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + View [] menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == menuBar).ToArray (); + Assert.Empty (menus); + Assert.Null (cm.MenuBar); + + Assert.True (Application.OnKeyDown (Key.F.WithAlt)); + Assert.True (menuBar.IsMenuOpen); + Assert.Equal (2, Application.Current!.Subviews.Count); + menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == menuBar).ToArray (); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.N.WithAlt)); + Assert.True (Application.OnKeyDown (Key.N.WithAlt)); + Assert.False (menuBar.IsMenuOpen); + Assert.False (Application.OnKeyDown (Key.R.WithAlt)); + Application.MainLoop!.RunIteration (); + Assert.True (newFile); + Assert.False (renameFile); + + newFile = false; + + cm.Show (menuItems); + Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.WithAlt)); + Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.NoShift)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.NoShift)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.E.WithAlt)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.E.NoShift)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + Assert.True (cm.MenuBar!.IsMenuOpen); + Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.F.WithAlt)); + Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.F.NoShift)); + Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt)); + Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.N.NoShift)); + Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.E.WithAlt)); + Assert.False (cm.MenuBar!.KeyBindings.Bindings.ContainsKey (Key.E.NoShift)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + Assert.Equal (3, Application.Current!.Subviews.Count); + menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == cm.MenuBar).ToArray (); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.E.WithAlt)); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.E.NoShift)); + Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + Assert.True (cm.MenuBar.IsMenuOpen); + Assert.True (Application.OnKeyDown (Key.F.WithAlt)); + Assert.False (cm.MenuBar.IsMenuOpen); + Assert.True (Application.OnKeyDown (Key.N.WithAlt)); + Application.MainLoop!.RunIteration (); + Assert.True (newFile); + + cm.Show (menuItems); + Assert.True (cm.MenuBar.IsMenuOpen); + Assert.Equal (3, Application.Current!.Subviews.Count); + menus = Application.Current!.Subviews.Where (v => v is Menu m && m.Host == cm.MenuBar).ToArray (); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.E.WithAlt)); + Assert.True (menus [0].KeyBindings.Bindings.ContainsKey (Key.E.NoShift)); + Assert.False (menus [0].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.False (menus [0].KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + Assert.False (menus [1].KeyBindings.Bindings.ContainsKey (Key.E.WithAlt)); + Assert.False (menus [1].KeyBindings.Bindings.ContainsKey (Key.E.NoShift)); + Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.True (menus [1].KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + Assert.True (Application.OnKeyDown (Key.E.NoShift)); + Assert.True (Application.OnKeyDown (Key.R.WithAlt)); + Assert.False (cm.MenuBar.IsMenuOpen); + Application.MainLoop!.RunIteration (); + Assert.True (renameFile); + + Assert.Single (Application.Current!.Subviews); + Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.WithAlt)); + Assert.True (menuBar.KeyBindings.Bindings.ContainsKey (Key.F.NoShift)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.WithAlt)); + Assert.False (menuBar.KeyBindings.Bindings.ContainsKey (Key.N.NoShift)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.E.WithAlt)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.E.NoShift)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.WithAlt)); + Assert.False (cm.MenuBar.KeyBindings.Bindings.ContainsKey (Key.R.NoShift)); + + newFile = false; + renameFile = false; + Assert.True (Application.OnKeyDown (Key.F.WithAlt)); + Assert.True (Application.OnKeyDown (Key.N.WithAlt)); + Assert.False (Application.OnKeyDown (Key.R.WithAlt)); + Application.MainLoop!.RunIteration (); + Assert.True (newFile); + Assert.False (renameFile); + + top.Dispose (); + + void New () { newFile = true; } + + void Rename () { renameFile = true; } + } + + [Fact] + [AutoInitShutdown] + public void Opened_MenuBar_Is_Closed_When_Another_MenuBar_Is_Opening_Also_By_HotKey () + { + var menuBar = new MenuBar + { + Menus = + [ + new ( + "_File", + new MenuItem [] + { + new ("_New", string.Empty, null) + }) + ] + }; + var cm = new ContextMenu (); + + var menuItems = new MenuBarItem ( + [ + new MenuBarItem ( + "_Edit", + new MenuItem [] + { + new ("_Rename File", string.Empty, null) + } + ) + ] + ); + var top = new Toplevel (); + top.Add (menuBar); + Application.Begin (top); + + Assert.True (Application.OnKeyDown (Key.F.WithAlt)); + Assert.True (menuBar.IsMenuOpen); + + cm.Show (menuItems); + Assert.False (menuBar.IsMenuOpen); + Assert.True (cm.MenuBar!.IsMenuOpen); + + Assert.True (Application.OnKeyDown (Key.F.WithAlt)); + Assert.True (menuBar.IsMenuOpen); + Assert.False (cm.MenuBar!.IsMenuOpen); + + top.Dispose (); + } +} \ No newline at end of file