From d84c4b285aa99b8344cf752829f6296dd5610560 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 17 Jun 2022 00:05:31 +0100 Subject: [PATCH] Fixes #1825. Parent MenuItem stay focused if child MenuItem is empty. --- Terminal.Gui/Views/Menu.cs | 23 +++-- UnitTests/MenuTests.cs | 188 +++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 10 deletions(-) diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index a6eed77d2..29672f7e6 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -422,8 +422,11 @@ namespace Terminal.Gui { AddCommand (Command.Left, () => { this.host.PreviousMenu (true); return true; }); AddCommand (Command.Right, () => { this.host.NextMenu (!this.barItems.IsTopLevel || (this.barItems.Children != null - && current > -1 && current < this.barItems.Children.Length && this.barItems.Children [current].IsFromSubMenu), - current > -1 && host.UseSubMenusSingleFrame && this.barItems.SubMenu (this.barItems.Children [current]) != null); + && this.barItems.Children.Length > 0 && current > -1 + && current < this.barItems.Children.Length && this.barItems.Children [current].IsFromSubMenu), + this.barItems.Children != null && this.barItems.Children.Length > 0 && current > -1 + && host.UseSubMenusSingleFrame && this.barItems.SubMenu (this.barItems.Children [current]) != null); + return true; }); AddCommand (Command.Cancel, () => { CloseAllMenus (); return true; }); @@ -1296,11 +1299,11 @@ namespace Terminal.Gui { previousFocused = SuperView == null ? Application.Current.Focused : SuperView.Focused; OpenMenu (idx, sIdx, subMenu); - if (!SelectEnabledItem (openCurrentMenu.barItems.Children, openCurrentMenu.current, out openCurrentMenu.current) - && subMenu == null && !CloseMenu (false)) { + //if (!SelectEnabledItem (openCurrentMenu.barItems.Children, openCurrentMenu.current, out openCurrentMenu.current) + // && subMenu == null && !CloseMenu (false)) { - return; - } + // return; + //} SetNeedsDisplay (); } @@ -1531,9 +1534,9 @@ namespace Terminal.Gui { OpenMenu (selected); if (!SelectEnabledItem (openCurrentMenu.barItems.Children, openCurrentMenu.current, out openCurrentMenu.current, false)) { openCurrentMenu.current = 0; - if (!SelectEnabledItem (openCurrentMenu.barItems.Children, openCurrentMenu.current, out openCurrentMenu.current)) { - CloseMenu (ignoreUseSubMenusSingleFrame); - } + //if (!SelectEnabledItem (openCurrentMenu.barItems.Children, openCurrentMenu.current, out openCurrentMenu.current, false)) { + // CloseMenu (ignoreUseSubMenusSingleFrame); + //} } break; case true: @@ -1570,7 +1573,7 @@ namespace Terminal.Gui { NextMenu (false, ignoreUseSubMenusSingleFrame); } } else { - var subMenu = openCurrentMenu.current > -1 + var subMenu = openCurrentMenu.current > -1 && openCurrentMenu.barItems.Children.Length > 0 ? openCurrentMenu.barItems.SubMenu (openCurrentMenu.barItems.Children [openCurrentMenu.current]) : null; if ((selectedSub == -1 || openSubMenu == null || openSubMenu?.Count == selectedSub) && subMenu == null) { diff --git a/UnitTests/MenuTests.cs b/UnitTests/MenuTests.cs index 5f84d4304..255b7f52e 100644 --- a/UnitTests/MenuTests.cs +++ b/UnitTests/MenuTests.cs @@ -1296,5 +1296,193 @@ Edit Assert.False (menu.UseKeysUpDownAsKeysLeftRight); Assert.True (menu.UseSubMenusSingleFrame); } + + [Fact, AutoInitShutdown] + public void Parent_MenuItem_Stay_Focused_If_Child_MenuItem_Is_Empty_By_Mouse () + { + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("New", "", null) + }), + new MenuBarItem ("Edit", new MenuItem [] { + }), + new MenuBarItem ("Format", new MenuItem [] { + new MenuItem ("Wrap", "", null) + }) + }); + var tf = new TextField () { Y = 2, Width = 10 }; + Application.Top.Add (menu, tf); + + Application.Begin (Application.Top); + Assert.True (tf.HasFocus); + Assert.True (menu.MouseEvent (new MouseEvent () { X = 1, Y = 0, Flags = MouseFlags.Button1Pressed, View = menu })); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + var expected = @" + File Edit Format +┌──────┐ +│ New │ +└──────┘ +"; + + var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 4), pos); + + Assert.True (menu.MouseEvent (new MouseEvent () { X = 8, Y = 0, Flags = MouseFlags.ReportMousePosition, View = menu })); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 1), pos); + + Assert.True (menu.MouseEvent (new MouseEvent () { X = 15, Y = 0, Flags = MouseFlags.ReportMousePosition, View = menu })); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format + ┌───────┐ + │ Wrap │ + └───────┘ +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 23, 4), pos); + + Assert.True (menu.MouseEvent (new MouseEvent () { X = 8, Y = 0, Flags = MouseFlags.ReportMousePosition, View = menu })); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 1), pos); + + Assert.True (menu.MouseEvent (new MouseEvent () { X = 1, Y = 0, Flags = MouseFlags.ReportMousePosition, View = menu })); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format +┌──────┐ +│ New │ +└──────┘ +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 4), pos); + + Assert.True (menu.MouseEvent (new MouseEvent () { X = 8, Y = 0, Flags = MouseFlags.Button1Pressed, View = menu })); + Assert.False (menu.IsMenuOpen); + Assert.True (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 1), pos); + } + + [Fact, AutoInitShutdown] + public void Parent_MenuItem_Stay_Focused_If_Child_MenuItem_Is_Empty_By_Keyboard () + { + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("New", "", null) + }), + new MenuBarItem ("Edit", new MenuItem [] { + }), + new MenuBarItem ("Format", new MenuItem [] { + new MenuItem ("Wrap", "", null) + }) + }); + var tf = new TextField () { Y = 2, Width = 10 }; + Application.Top.Add (menu, tf); + + Application.Begin (Application.Top); + Assert.True (tf.HasFocus); + Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + var expected = @" + File Edit Format +┌──────┐ +│ New │ +└──────┘ +"; + + var pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 4), pos); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 1), pos); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format + ┌───────┐ + │ Wrap │ + └───────┘ +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 23, 4), pos); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ()))); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 1), pos); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorLeft, new KeyModifiers ()))); + Assert.True (menu.IsMenuOpen); + Assert.False (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format +┌──────┐ +│ New │ +└──────┘ +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 4), pos); + + Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + Assert.False (menu.IsMenuOpen); + Assert.True (tf.HasFocus); + Application.Top.Redraw (Application.Top.Bounds); + expected = @" + File Edit Format +"; + + pos = GraphViewTests.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (2, 0, 22, 1), pos); + } } }