diff --git a/Terminal.Gui/Core/View.cs b/Terminal.Gui/Core/View.cs index 60e5242c0..2c51d48ee 100644 --- a/Terminal.Gui/Core/View.cs +++ b/Terminal.Gui/Core/View.cs @@ -987,13 +987,13 @@ namespace Terminal.Gui { if (view == null || subviews == null) return; - SetNeedsLayout (); - SetNeedsDisplay (); var touched = view.Frame; subviews.Remove (view); tabIndexes.Remove (view); view.container = null; view.tabIndex = -1; + SetNeedsLayout (); + SetNeedsDisplay (); if (subviews.Count < 1) { CanFocus = false; } diff --git a/Terminal.Gui/Core/Window.cs b/Terminal.Gui/Core/Window.cs index d0811eb16..85c8929cc 100644 --- a/Terminal.Gui/Core/Window.cs +++ b/Terminal.Gui/Core/Window.cs @@ -277,18 +277,17 @@ namespace Terminal.Gui { { var padding = Border.GetSumThickness (); var scrRect = ViewToScreen (new Rect (0, 0, Frame.Width, Frame.Height)); - //var borderLength = Border.DrawMarginFrame ? 1 : 0; - // FIXED: Why do we draw the frame twice? This call is here to clear the content area, I think. Why not just clear that area? - if (!NeedDisplay.IsEmpty) { + if (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded) { Driver.SetAttribute (GetNormalColor ()); Clear (); + contentView.SetNeedsDisplay (); } var savedClip = contentView.ClipToBounds (); // Redraw our contentView // DONE: smartly constrict contentView.Bounds to just be what intersects with the 'bounds' we were passed - contentView.Redraw (!NeedDisplay.IsEmpty ? contentView.Bounds : bounds); + contentView.Redraw (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded ? contentView.Bounds : bounds); Driver.Clip = savedClip; ClearLayoutNeeded (); diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 04d54745a..2244531d1 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -690,6 +690,7 @@ namespace Terminal.Gui { } } while (barItems.Children [current] == null || disabled); SetNeedsDisplay (); + SetParentSetNeedsDisplay (); if (!host.UseSubMenusSingleFrame) host.OnMenuOpened (); return true; @@ -737,11 +738,24 @@ namespace Terminal.Gui { } } while (barItems.Children [current] == null || disabled); SetNeedsDisplay (); + SetParentSetNeedsDisplay (); if (!host.UseSubMenusSingleFrame) host.OnMenuOpened (); return true; } + private void SetParentSetNeedsDisplay () + { + if (host.openSubMenu != null) { + foreach (var menu in host.openSubMenu) { + menu.SetNeedsDisplay (); + } + } + + host?.openMenu.SetNeedsDisplay (); + host.SetNeedsDisplay (); + } + public override bool MouseEvent (MouseEvent me) { if (!host.handled && !host.HandleGrabView (me, this)) { @@ -778,6 +792,7 @@ namespace Terminal.Gui { current = me.Y - 1; if (host.UseSubMenusSingleFrame || !CheckSubMenu ()) { SetNeedsDisplay (); + SetParentSetNeedsDisplay (); return true; } host.OnMenuOpened (); @@ -806,6 +821,7 @@ namespace Terminal.Gui { return host.CloseMenu (false, true); } else { SetNeedsDisplay (); + SetParentSetNeedsDisplay (); } return true; } @@ -1589,7 +1605,7 @@ namespace Terminal.Gui { 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) { + if ((selectedSub == -1 || openSubMenu == null || openSubMenu?.Count - 1 == selectedSub) && subMenu == null) { if (openSubMenu != null && !CloseMenu (false, true)) return; NextMenu (false, ignoreUseSubMenusSingleFrame); diff --git a/UnitTests/MenuTests.cs b/UnitTests/MenuTests.cs index 96313ea1c..e41041e58 100644 --- a/UnitTests/MenuTests.cs +++ b/UnitTests/MenuTests.cs @@ -1654,5 +1654,85 @@ Edit Assert.True (menu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); Assert.True (menu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); } + + [Fact, AutoInitShutdown] + public void MenuBar_In_Window_Without_Other_Views () + { + var win = new Window (); + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("New", "", null) + }), + new MenuBarItem ("Edit", new MenuItem [] { + new MenuBarItem ("Delete", new MenuItem [] { + new MenuItem ("All", "", null), + new MenuItem ("Selected", "", null) + }) + }) + }); ; + win.Add (menu); + var top = Application.Top; + top.Add (win); + Application.Begin (top); + ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (win.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + win.Redraw (win.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│┌──────┐ │ +││ New │ │ +│└──────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + win.Redraw (win.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│ │ +│ └─────────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + win.Redraw (win.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│┌───────────┐ │ +│ └─────────┘│ All │ │ +│ │ Selected │ │ +│ └───────────┘ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + win.Redraw (win.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│┌──────┐ │ +││ New │ │ +│└──────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + } } }