From fa0085d9e4ee55ce893b4f1e9be27e476f953363 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 1 Sep 2024 20:18:53 +0100 Subject: [PATCH] ix some more bug, cleanup code and add more unit tests. --- Terminal.Gui/Views/ColorPicker.cs | 2 +- Terminal.Gui/Views/Menu/ContextMenu.cs | 8 +- Terminal.Gui/Views/Menu/Menu.cs | 2 +- Terminal.Gui/Views/Menu/MenuBar.cs | 28 ++- Terminal.Gui/Views/Menu/MenuItem.cs | 4 +- UICatalog/Scenarios/ContextMenus.cs | 12 +- UICatalog/Scenarios/DynamicMenuBar.cs | 44 ++-- UICatalog/UICatalog.cs | 2 +- UnitTests/Views/ContextMenuTests.cs | 307 +++++++++++++++++++++++-- 9 files changed, 351 insertions(+), 58 deletions(-) diff --git a/Terminal.Gui/Views/ColorPicker.cs b/Terminal.Gui/Views/ColorPicker.cs index dff7d8133..00d6ee3f5 100644 --- a/Terminal.Gui/Views/ColorPicker.cs +++ b/Terminal.Gui/Views/ColorPicker.cs @@ -361,7 +361,7 @@ public class ColorPicker : View } } - + /// protected override void Dispose (bool disposing) { DisposeOldViews (); diff --git a/Terminal.Gui/Views/Menu/ContextMenu.cs b/Terminal.Gui/Views/Menu/ContextMenu.cs index 0ceec6d74..8751ada92 100644 --- a/Terminal.Gui/Views/Menu/ContextMenu.cs +++ b/Terminal.Gui/Views/Menu/ContextMenu.cs @@ -58,7 +58,7 @@ public sealed class ContextMenu : IDisposable 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 @@ public sealed class ContextMenu : IDisposable 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 @@ public sealed class ContextMenu : IDisposable if (menuItem.ShortcutKey != Key.Empty) { // Remove an existent ShortcutKey - _menuBar?.KeyBindings.Remove (menuItem.ShortcutKey); + _menuBar?.KeyBindings.Remove (menuItem.ShortcutKey!); } } } @@ -171,7 +171,7 @@ public sealed class ContextMenu : IDisposable 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 5bb224399..9fcf3fd4c 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 1415c2d76..76c00ed19 100644 --- a/Terminal.Gui/Views/Menu/MenuBar.cs +++ b/Terminal.Gui/Views/Menu/MenuBar.cs @@ -126,7 +126,12 @@ public class MenuBar : View, IDesignable 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 class MenuBar : View, IDesignable mbar?.CleanUp (); + CloseOtherOpenedMenuBar (); + if (!Enabled || _openMenu is { }) { return; @@ -528,11 +535,16 @@ public class MenuBar : View, IDesignable _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 @@ public class MenuBar : View, IDesignable else if (subMenu != null || (OpenCurrentMenu._currentChild > -1 && !OpenCurrentMenu.BarItems! - .Children! [OpenCurrentMenu._currentChild] + .Children! [OpenCurrentMenu._currentChild]! .IsFromSubMenu)) { _selectedSub++; @@ -999,7 +1011,7 @@ public class MenuBar : View, IDesignable } internal bool SelectEnabledItem ( - IEnumerable? children, + MenuItem? []? children, int current, out int newCurrent, bool forward = true @@ -1012,11 +1024,11 @@ public class MenuBar : View, IDesignable 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 @@ public class MenuBar : View, IDesignable 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 b99f5f83c..0c920da52 100644 --- a/Terminal.Gui/Views/Menu/MenuItem.cs +++ b/Terminal.Gui/Views/Menu/MenuItem.cs @@ -351,10 +351,10 @@ public class MenuItem { 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 477fa1198..01c4e340e 100644 --- a/UICatalog/Scenarios/ContextMenus.cs +++ b/UICatalog/Scenarios/ContextMenus.cs @@ -98,8 +98,8 @@ public class ContextMenus : Scenario 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 @@ public class ContextMenus : Scenario MenuBarItem menuItems = new ( new [] { + new MenuBarItem ( + "_Languages", + GetSupportedCultures () + ), new ( "_Configuration", "Show configuration", @@ -214,10 +218,6 @@ public class ContextMenus : Scenario ) } ), - new MenuBarItem ( - "_Languages", - GetSupportedCultures () - ), _miForceMinimumPosToZero = new ( "Fo_rceMinimumPosToZero", diff --git a/UICatalog/Scenarios/DynamicMenuBar.cs b/UICatalog/Scenarios/DynamicMenuBar.cs index ad00a9a69..2cfbe93a4 100644 --- a/UICatalog/Scenarios/DynamicMenuBar.cs +++ b/UICatalog/Scenarios/DynamicMenuBar.cs @@ -875,7 +875,7 @@ public class DynamicMenuBar : Scenario { 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 class DynamicMenuBar : Scenario _lstMenus.SelectedItem = _lstMenus.Source.Count - 1; } + if (_menuBar.Menus.Length == 0) + { + RemoveMenuBar (); + } + _lstMenus.SetNeedsDisplay (); SetFrameDetails (); } @@ -992,7 +997,7 @@ public class DynamicMenuBar : Scenario } var newMenu = CreateNewMenu (item) as MenuBarItem; - newMenu.AddMenuBarItem (); + newMenu.AddMenuBarItem (MenuBar); _currentMenuBarItem = newMenu; _currentMenuBarItem.CheckType = item.CheckStyle; @@ -1012,7 +1017,7 @@ public class DynamicMenuBar : Scenario btnRemoveMenuBar.Accept += (s, e) => { - if (_menuBar == null || _menuBar.Menus.Length == 0) + if (_menuBar == null) { return; } @@ -1033,25 +1038,30 @@ public class DynamicMenuBar : Scenario : 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 6723d9876..471e0984a 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -875,7 +875,7 @@ public class UICatalogApp }; } - Enum GetDiagnosticsEnumValue (string title) + Enum GetDiagnosticsEnumValue (string? title) { return title switch { diff --git a/UnitTests/Views/ContextMenuTests.cs b/UnitTests/Views/ContextMenuTests.cs index e31170b3c..0872e2de9 100644 --- a/UnitTests/Views/ContextMenuTests.cs +++ b/UnitTests/Views/ContextMenuTests.cs @@ -19,10 +19,10 @@ public class ContextMenuTests (ITestOutputHelper output) 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 class ContextMenuTests (ITestOutputHelper output) var view = new View { X = 5, Y = 10 }; top.Add (view); + cm = new ContextMenu { Host = view, @@ -74,6 +75,7 @@ public class ContextMenuTests (ITestOutputHelper output) new MenuItem ("Two", "", null) ] ); + var menu = new MenuBar { Menus = @@ -401,6 +403,7 @@ public class ContextMenuTests (ITestOutputHelper output) 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 class ContextMenuTests (ITestOutputHelper output) 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 @@ public class ContextMenuTests (ITestOutputHelper output) 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 @@ public class ContextMenuTests (ITestOutputHelper output) 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 @@ public class ContextMenuTests (ITestOutputHelper output) 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 @@ public class ContextMenuTests (ITestOutputHelper output) 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 class ContextMenuTests (ITestOutputHelper output) 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 class ContextMenuTests (ITestOutputHelper output) 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 class ContextMenuTests (ITestOutputHelper output) [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 class ContextMenuTests (ITestOutputHelper output) 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 class ContextMenuTests (ITestOutputHelper output) 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 class ContextMenuTests (ITestOutputHelper output) 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 class ContextMenuTests (ITestOutputHelper output) 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