From 9ff50d3825aaad5ec5bc37ce1b42f1efe4cdaac9 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 21 Apr 2023 00:16:20 +0100 Subject: [PATCH 01/16] Fixes #2558. MenuBar positions wrong in some situations. --- Terminal.Gui/Application.cs | 6 +- Terminal.Gui/View/View.cs | 28 +- Terminal.Gui/View/ViewLayout.cs | 4 +- Terminal.Gui/Views/ContextMenu.cs | 6 +- Terminal.Gui/Views/Menu.cs | 54 +- UICatalog/Scenarios/DynamicMenuBar.cs | 42 +- UnitTests/View/NavigationTests.cs | 253 ++++++++- UnitTests/Views/ContextMenuTests.cs | 47 +- UnitTests/Views/MenuTests.cs | 780 +++++++++++++++++--------- 9 files changed, 906 insertions(+), 314 deletions(-) diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs index 3f0baed243..3b0677f40d 100644 --- a/Terminal.Gui/Application.cs +++ b/Terminal.Gui/Application.cs @@ -1203,9 +1203,9 @@ static void OnUnGrabbedMouse (View view) static void ProcessMouseEvent (MouseEvent me) { - bool OutsideFrame (Point p, Rect r) + bool OutsideBounds (Point p, Rect r) { - return p.X < 0 || p.X > r.Width - 1 || p.Y < 0 || p.Y > r.Height - 1; + return p.X < 0 || p.X > r.Right || p.Y < 0 || p.Y > r.Bottom; } if (IsMouseDisabled) { @@ -1238,7 +1238,7 @@ bool OutsideFrame (Point p, Rect r) OfY = me.Y - newxy.Y, View = view }; - if (OutsideFrame (new Point (nme.X, nme.Y), _mouseGrabView.Frame)) { + if (OutsideBounds (new Point (nme.X, nme.Y), _mouseGrabView.Bounds)) { _lastMouseOwnerView?.OnMouseLeave (me); } //System.Diagnostics.Debug.WriteLine ($"{nme.Flags};{nme.X};{nme.Y};{mouseGrabView}"); diff --git a/Terminal.Gui/View/View.cs b/Terminal.Gui/View/View.cs index 7e662a72fe..977d24fddb 100644 --- a/Terminal.Gui/View/View.cs +++ b/Terminal.Gui/View/View.cs @@ -321,6 +321,17 @@ public void EndInit () /// public static ConsoleDriver Driver => Application.Driver; + /// + /// Gets the current driver in use by the view. + /// + public static Rect DriverFrame => new (0, 0, Driver.Cols, Driver.Rows); + + /// + /// Gets the current driver location and dimension in use by the view + /// offset by the location and dimension. + /// + public static (Point Location, Point Dimension) DriverFrameOffset => new (new Point (Application.Top.Frame.X, Application.Top.Frame.Y), new (Application.Top.Frame.X + Application.Top.Frame.Width - Driver.Cols, Application.Top.Frame.Y + Application.Top.Frame.Height - Driver.Rows)); + /// /// Gets or sets arbitrary data for the view. /// @@ -434,7 +445,7 @@ public override bool Enabled { } } } - + /// /// Event fired when the value is being changed. /// @@ -481,7 +492,7 @@ bool CanBeVisible (View view) return true; } - + /// /// Pretty prints the View /// @@ -508,5 +519,18 @@ protected override void Dispose (bool disposing) } base.Dispose (disposing); } + + /// + /// Gets the superview location offset relative to the . + /// + /// + /// The location offset and the respective superview. + public Point GetDriverLocationOffset (View superView) + { + var superViewFrame = superView == null || (superView == Application.Top && SuperView != superView) ? DriverFrame : superView.Frame; + var sv = superView == null ? Application.Top : superView; + return new Point (superViewFrame.X - sv.Frame.X - (superViewFrame.X != sv.Frame.X ? 1 : 0), + superViewFrame.Y - sv.Frame.Y - (superViewFrame.Y != sv.Frame.Y ? 1 : 0)); + } } } diff --git a/Terminal.Gui/View/ViewLayout.cs b/Terminal.Gui/View/ViewLayout.cs index 187d3cb6c5..b88690c1fd 100644 --- a/Terminal.Gui/View/ViewLayout.cs +++ b/Terminal.Gui/View/ViewLayout.cs @@ -495,7 +495,7 @@ protected void ClearLayoutNeeded () public Point ScreenToView (int x, int y) { if (SuperView == null) { - return new Point (x - Frame.X, y - _frame.Y); + return new Point (x - _frame.X, y - _frame.Y); } else { var parent = SuperView.ScreenToView (x, y); return new Point (parent.X - _frame.X, parent.Y - _frame.Y); @@ -512,7 +512,7 @@ public Point ScreenToBounds (int x, int y) { if (SuperView == null) { var boundsOffset = GetBoundsOffset (); - return new Point (x - Frame.X + boundsOffset.X, y - Frame.Y + boundsOffset.Y); + return new Point (x - _frame.X + boundsOffset.X, y - _frame.Y + boundsOffset.Y); } else { var parent = SuperView.ScreenToView (x, y); return new Point (parent.X - _frame.X, parent.Y - _frame.Y); diff --git a/Terminal.Gui/Views/ContextMenu.cs b/Terminal.Gui/Views/ContextMenu.cs index 13f0b66f2b..64ebf719e8 100644 --- a/Terminal.Gui/Views/ContextMenu.cs +++ b/Terminal.Gui/Views/ContextMenu.cs @@ -94,10 +94,10 @@ public void Show () container = Application.Top; container.Closing += Container_Closing; container.TerminalResized += Container_Resized; - var frame = container.Frame; + var frame = View.DriverFrame; var position = Position; if (Host != null) { - Host.ViewToScreen (container.Frame.X, container.Frame.Y, out int x, out int y); + Host.ViewToScreen (frame.X, frame.Y, out int x, out int y); var pos = new Point (x, y); pos.Y += Host.Frame.Height - 1; if (position != pos) { @@ -119,7 +119,7 @@ public void Show () if (Host == null) { position.Y = frame.Bottom - rect.Height - 1; } else { - Host.ViewToScreen (container.Frame.X, container.Frame.Y, out int x, out int y); + Host.ViewToScreen (frame.X, frame.Y, out int x, out int y); var pos = new Point (x, y); position.Y = pos.Y - rect.Height - 1; } diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 9dd5ea5562..34d0da8393 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -512,7 +512,15 @@ public Menu (MenuBar host, int x, int y, MenuBarItem barItems, Menu parent = nul private void Application_RootMouseEvent (MouseEvent me) { - var view = View.FindDeepestView (this, me.X, me.Y, out int rx, out int ry); + if (me.View is MenuBar) { + return; + } + var locationOffset = GetDriverLocationOffset (null); + if (SuperView != null) { + locationOffset.X += SuperView.Border.Thickness.Left; + locationOffset.Y += SuperView.Border.Thickness.Top; + } + var view = View.FindDeepestView (this, me.X + locationOffset.X, me.Y + locationOffset.Y, out int rx, out int ry); if (view == this) { var nme = new MouseEvent () { X = rx, @@ -540,8 +548,8 @@ public override void Redraw (Rect bounds) if (barItems.Children == null) { return; } - var savedClip = Application.Driver.Clip; - Application.Driver.Clip = Application.Top.Frame; + var savedClip = Driver.Clip; + Driver.Clip = DriverFrame; Driver.SetAttribute (GetNormalColor ()); @@ -549,8 +557,12 @@ public override void Redraw (Rect bounds) OnRenderLineCanvas (); for (int i = Bounds.Y; i < barItems.Children.Length; i++) { - if (i < 0) + if (i < 0) { continue; + } + if (ViewToScreen (Bounds).Y + i >= Driver.Rows) { + break; + } var item = barItems.Children [i]; Driver.SetAttribute (item == null ? GetNormalColor () : i == current ? ColorScheme.Focus : GetNormalColor ()); @@ -858,12 +870,17 @@ public override bool MouseEvent (MouseEvent me) } host.handled = false; bool disabled; - var meYOffset = BorderStyle != LineStyle.None ? 1 : 0; + Point locationOffset = default; + if (SuperView != null) { + locationOffset.X += SuperView.Border.Thickness.Left; + locationOffset.Y += SuperView.Border.Thickness.Top; + } + var meYOffset = Border.Thickness.Top + locationOffset.Y; + var meY = me.Y - meYOffset; if (me.Flags == MouseFlags.Button1Clicked) { disabled = false; - if (me.Y < meYOffset) + if (meY < 0) return true; - var meY = me.Y - meYOffset; if (meY >= barItems.Children.Length) return true; var item = barItems.Children [meY]; @@ -878,14 +895,14 @@ public override bool MouseEvent (MouseEvent me) me.Flags.HasFlag (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition)) { disabled = false; - if (me.Y < meYOffset || me.Y - meYOffset >= barItems.Children.Length) { + if (meY < 0 || meY >= barItems.Children.Length) { return true; } - var item = barItems.Children [me.Y - meYOffset]; + var item = barItems.Children [meY]; if (item == null) return true; if (item == null || !item.IsEnabled ()) disabled = true; if (item != null && !disabled) - current = me.Y - meYOffset; + current = meY; if (host.UseSubMenusSingleFrame || !CheckSubMenu ()) { SetNeedsDisplay (); SetParentSetNeedsDisplay (); @@ -1390,12 +1407,12 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem subMenu = null) // text belonging to the menu for (int i = 0; i < index; i++) pos += Menus [i].TitleLength + (Menus [i].Help.ConsoleWidth > 0 ? Menus [i].Help.ConsoleWidth + 2 : 0) + leftPadding + rightPadding; + var superView = SuperView == null ? Application.Top : SuperView; - Point locationOffset; - if (superView.BorderStyle != LineStyle.None) { - locationOffset = new Point (superView.Frame.X + 1, superView.Frame.Y + 1); - } else { - locationOffset = new Point (superView.Frame.X, superView.Frame.Y); + var locationOffset = GetDriverLocationOffset (superView); + if (superView != Application.Top) { + locationOffset.X += superView.Border.Thickness.Left; + locationOffset.Y += superView.Border.Thickness.Top; } openMenu = new Menu (this, Frame.X + pos + locationOffset.X, Frame.Y + 1 + locationOffset.Y, Menus [index], null, MenusBorderStyle); openCurrentMenu = openMenu; @@ -1923,7 +1940,12 @@ public override bool MouseEvent (MouseEvent me) (me.Flags == MouseFlags.ReportMousePosition && selected > -1) || (me.Flags.HasFlag (MouseFlags.Button1Pressed | MouseFlags.ReportMousePosition) && selected > -1)) { int pos = xOrigin; - int cx = me.X; + Point locationOffset = default; + if (SuperView != null) { + locationOffset.X += SuperView.Border.Thickness.Left; + locationOffset.Y += SuperView.Border.Thickness.Top; + } + int cx = me.X - locationOffset.X; for (int i = 0; i < Menus.Length; i++) { if (cx >= pos && cx < pos + leftPadding + Menus [i].TitleLength + Menus [i].Help.ConsoleWidth + rightPadding) { if (me.Flags == MouseFlags.Button1Clicked) { diff --git a/UICatalog/Scenarios/DynamicMenuBar.cs b/UICatalog/Scenarios/DynamicMenuBar.cs index 18ce15d63b..a671e6494e 100644 --- a/UICatalog/Scenarios/DynamicMenuBar.cs +++ b/UICatalog/Scenarios/DynamicMenuBar.cs @@ -208,7 +208,7 @@ public DynamicMenuBarSample () : base () }; Add (_frmMenuDetails); - _btnMenuBarUp.Clicked += (s,e) => { + _btnMenuBarUp.Clicked += (s, e) => { var i = _currentSelectedMenuBar; var menuItem = _menuBar != null && _menuBar.Menus.Length > 0 ? _menuBar.Menus [i] : null; if (menuItem != null) { @@ -222,7 +222,7 @@ public DynamicMenuBarSample () : base () } }; - _btnMenuBarDown.Clicked += (s,e) => { + _btnMenuBarDown.Clicked += (s, e) => { var i = _currentSelectedMenuBar; var menuItem = _menuBar != null && _menuBar.Menus.Length > 0 ? _menuBar.Menus [i] : null; if (menuItem != null) { @@ -236,7 +236,7 @@ public DynamicMenuBarSample () : base () } }; - _btnUp.Clicked += (s,e) => { + _btnUp.Clicked += (s, e) => { var i = _lstMenus.SelectedItem; var menuItem = DataContext.Menus.Count > 0 ? DataContext.Menus [i].MenuItem : null; if (menuItem != null) { @@ -251,7 +251,7 @@ public DynamicMenuBarSample () : base () } }; - _btnDown.Clicked += (s,e) => { + _btnDown.Clicked += (s, e) => { var i = _lstMenus.SelectedItem; var menuItem = DataContext.Menus.Count > 0 ? DataContext.Menus [i].MenuItem : null; if (menuItem != null) { @@ -266,7 +266,7 @@ public DynamicMenuBarSample () : base () } }; - _btnPreviowsParent.Clicked += (s,e) => { + _btnPreviowsParent.Clicked += (s, e) => { if (_currentMenuBarItem != null && _currentMenuBarItem.Parent != null) { var mi = _currentMenuBarItem; _currentMenuBarItem = _currentMenuBarItem.Parent as MenuBarItem; @@ -295,16 +295,16 @@ public DynamicMenuBarSample () : base () X = Pos.Right (_btnOk) + 3, Y = Pos.Top (_btnOk), }; - _btnCancel.Clicked += (s,e) => { + _btnCancel.Clicked += (s, e) => { SetFrameDetails (_currentEditMenuBarItem); }; Add (_btnCancel); - _lstMenus.SelectedItemChanged += (s,e) => { + _lstMenus.SelectedItemChanged += (s, e) => { SetFrameDetails (); }; - _btnOk.Clicked += (s,e) => { + _btnOk.Clicked += (s, e) => { if (ustring.IsNullOrEmpty (_frmMenuDetails._txtTitle.Text) && _currentEditMenuBarItem != null) { MessageBox.ErrorQuery ("Invalid title", "Must enter a valid title!.", "Ok"); } else if (_currentEditMenuBarItem != null) { @@ -320,7 +320,7 @@ public DynamicMenuBarSample () : base () } }; - _btnAdd.Clicked += (s,e) => { + _btnAdd.Clicked += (s, e) => { if (MenuBar == null) { MessageBox.ErrorQuery ("Menu Bar Error", "Must add a MenuBar first!", "Ok"); _btnAddMenuBar.SetFocus (); @@ -357,7 +357,7 @@ public DynamicMenuBarSample () : base () } }; - _btnRemove.Clicked += (s,e) => { + _btnRemove.Clicked += (s, e) => { var menuItem = DataContext.Menus.Count > 0 ? DataContext.Menus [_lstMenus.SelectedItem].MenuItem : null; if (menuItem != null) { var childrens = ((MenuBarItem)_currentMenuBarItem).Children; @@ -389,7 +389,7 @@ public DynamicMenuBarSample () : base () } }; - _lstMenus.OpenSelectedItem += (s,e) => { + _lstMenus.OpenSelectedItem += (s, e) => { _currentMenuBarItem = DataContext.Menus [e.Item].MenuItem; if (!(_currentMenuBarItem is MenuBarItem)) { MessageBox.ErrorQuery ("Menu Open Error", "Must allows sub menus first!", "Ok"); @@ -403,18 +403,18 @@ public DynamicMenuBarSample () : base () }; _lstMenus.Enter += (s, e) => { - var menuBarItem = DataContext.Menus.Count > 0 ? DataContext.Menus [_lstMenus.SelectedItem].MenuItem : null; + var menuBarItem = _lstMenus.SelectedItem > -1 && DataContext.Menus.Count > 0 ? DataContext.Menus [_lstMenus.SelectedItem].MenuItem : null; SetFrameDetails (menuBarItem); }; - _btnNext.Clicked += (s,e) => { + _btnNext.Clicked += (s, e) => { if (_menuBar != null && _currentSelectedMenuBar + 1 < _menuBar.Menus.Length) { _currentSelectedMenuBar++; } SelectCurrentMenuBarItem (); }; - _btnPrevious.Clicked += (s,e) => { + _btnPrevious.Clicked += (s, e) => { if (_currentSelectedMenuBar - 1 > -1) { _currentSelectedMenuBar--; } @@ -428,7 +428,7 @@ public DynamicMenuBarSample () : base () } }; - _btnAddMenuBar.Clicked += (s,e) => { + _btnAddMenuBar.Clicked += (s, e) => { var frameDetails = new DynamicMenuBarDetails (null, false); var item = frameDetails.EnterMenuItem (); if (item == null) { @@ -455,7 +455,7 @@ public DynamicMenuBarSample () : base () _menuBar.SetNeedsDisplay (); }; - _btnRemoveMenuBar.Clicked += (s,e) => { + _btnRemoveMenuBar.Clicked += (s, e) => { if (_menuBar == null || _menuBar.Menus.Length == 0) { return; } @@ -505,7 +505,7 @@ void SetFrameDetails (MenuItem menuBarItem = null) MenuItem menuItem; if (menuBarItem == null) { - menuItem = DataContext.Menus.Count > 0 ? DataContext.Menus [_lstMenus.SelectedItem].MenuItem : null; + menuItem = _lstMenus.SelectedItem > -1 && DataContext.Menus.Count > 0 ? DataContext.Menus [_lstMenus.SelectedItem].MenuItem : null; } else { menuItem = menuBarItem; } @@ -778,7 +778,7 @@ bool CheckShortcut (Key k, bool pre) X = Pos.X (_lblShortcut), Y = Pos.Bottom (_txtShortcut) + 1 }; - _btnShortcut.Clicked += (s,e) => { + _btnShortcut.Clicked += (s, e) => { _txtShortcut.Text = ""; }; Add (_btnShortcut); @@ -829,7 +829,7 @@ bool CheckShortcut (Key k, bool pre) _txtShortcut.Enabled = _ckbIsTopLevel.Checked == false && _ckbSubMenu.Checked == false; } }; - _ckbNullCheck.Toggled += (s,e) => { + _ckbNullCheck.Toggled += (s, e) => { if (_menuItem != null) { _menuItem.AllowNullChecked = (bool)_ckbNullCheck.Checked; } @@ -861,7 +861,7 @@ public DynamicMenuItem EnterMenuItem () var _btnOk = new Button ("Ok") { IsDefault = true, }; - _btnOk.Clicked += (s,e) => { + _btnOk.Clicked += (s, e) => { if (ustring.IsNullOrEmpty (_txtTitle.Text)) { MessageBox.ErrorQuery ("Invalid title", "Must enter a valid title!.", "Ok"); } else { @@ -870,7 +870,7 @@ public DynamicMenuItem EnterMenuItem () } }; var _btnCancel = new Button ("Cancel"); - _btnCancel.Clicked += (s,e) => { + _btnCancel.Clicked += (s, e) => { _txtTitle.Text = ustring.Empty; Application.RequestStop (); }; diff --git a/UnitTests/View/NavigationTests.cs b/UnitTests/View/NavigationTests.cs index 61c5bb54c9..aed45485bf 100644 --- a/UnitTests/View/NavigationTests.cs +++ b/UnitTests/View/NavigationTests.cs @@ -46,7 +46,7 @@ public void FocusNearestView_Ensure_Focus_Ordered () top.ProcessKey (new KeyEvent (Key.BackTab | Key.ShiftMask, new KeyModifiers ())); Assert.Equal ($"WindowSubview", top.MostFocused.Text); } - + [Fact] public void Subviews_TabIndexes_AreEqual () @@ -949,7 +949,7 @@ public void WindowDispose_CanFocusProblem () // Assert does Not throw NullReferenceException top.SetFocus (); } - + [Fact, AutoInitShutdown] public void SetHasFocus_Do_Not_Throws_If_OnLeave_Remove_Focused_Changing_To_Null () { @@ -982,7 +982,7 @@ public void SetHasFocus_Do_Not_Throws_If_OnLeave_Remove_Focused_Changing_To_Null Assert.True (subView1Leave); Assert.False (subView1subView1Leave); } - + [Fact, AutoInitShutdown] public void Remove_Does_Not_Change_Focus () { @@ -1078,5 +1078,252 @@ public void FocusNext_Does_Not_Throws_If_A_View_Was_Removed_From_The_Collection Assert.True (removed); Assert.Null (view3); } + + + [Fact, AutoInitShutdown] + public void ScreenToView_ViewToScreen_FindDeepestView_Full_Top () + { + var top = Application.Top; + top.BorderStyle = LineStyle.Single; + var view = new View () { X = 3, Y = 2, Width = 10, Height = 1, Text = "0123456789" }; + top.Add (view); + + Application.Begin (top); + + Assert.Equal (Application.Top, top); + Assert.Equal (new Rect (0, 0, 80, 25), View.DriverFrame); + Assert.Equal (View.DriverFrame, top.Frame); + Assert.Equal (new Rect (0, 0, 80, 25), top.Frame); + Assert.Equal ((Point.Empty, Point.Empty), View.DriverFrameOffset); + + ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + Assert.Equal (View.DriverFrame, top.Frame); + Assert.Equal (new Rect (0, 0, 20, 10), top.Frame); + Assert.Equal ((Point.Empty, Point.Empty), View.DriverFrameOffset); + _ = TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────┐ +│ │ +│ │ +│ 0123456789 │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────┘", output); + + // top + Assert.Equal (Point.Empty, top.ScreenToView (0, 0)); + top.Margin.ViewToScreen (0, 0, out int col, out int row); + Assert.Equal (0, col); + Assert.Equal (0, row); + top.Border.ViewToScreen (0, 0, out col, out row); + Assert.Equal (0, col); + Assert.Equal (0, row); + top.Padding.ViewToScreen (0, 0, out col, out row); + Assert.Equal (0, col); + Assert.Equal (0, row); + top.ViewToScreen (0, 0, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + top.ViewToScreen (-1, -1, out col, out row); + Assert.Equal (0, col); + Assert.Equal (0, row); + Assert.Equal (top, View.FindDeepestView (top, 0, 0, out int rx, out int ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); + Assert.Equal (new Point (3, 2), top.ScreenToView (3, 2)); + top.ViewToScreen (3, 2, out col, out row); + Assert.Equal (4, col); + Assert.Equal (3, row); + Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry)); + Assert.Equal (3, rx); + Assert.Equal (2, ry); + Assert.Equal (new Point (13, 2), top.ScreenToView (13, 2)); + top.ViewToScreen (13, 2, out col, out row); + Assert.Equal (14, col); + Assert.Equal (3, row); + Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry)); + Assert.Equal (13, rx); + Assert.Equal (2, ry); + Assert.Equal (new Point (14, 3), top.ScreenToView (14, 3)); + top.ViewToScreen (14, 3, out col, out row); + Assert.Equal (15, col); + Assert.Equal (4, row); + Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry)); + Assert.Equal (14, rx); + Assert.Equal (3, ry); + // view + Assert.Equal (new Point (-3, -2), view.ScreenToView (0, 0)); + view.Margin.ViewToScreen (-3, -2, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + view.Border.ViewToScreen (-3, -2, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + view.Padding.ViewToScreen (-3, -2, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + view.ViewToScreen (-3, -2, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + view.ViewToScreen (-4, -3, out col, out row); + Assert.Equal (0, col); + Assert.Equal (0, row); + Assert.Equal (top, View.FindDeepestView (top, 0, 0, out rx, out ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); + Assert.Equal (Point.Empty, view.ScreenToView (3, 2)); + view.ViewToScreen (0, 0, out col, out row); + Assert.Equal (4, col); + Assert.Equal (3, row); + Assert.Equal (view, View.FindDeepestView (top, 4, 3, out rx, out ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); + Assert.Equal (new Point (10, 0), view.ScreenToView (13, 2)); + view.ViewToScreen (10, 0, out col, out row); + Assert.Equal (14, col); + Assert.Equal (3, row); + Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry)); + Assert.Equal (14, rx); + Assert.Equal (3, ry); + Assert.Equal (new Point (11, 1), view.ScreenToView (14, 3)); + view.ViewToScreen (11, 1, out col, out row); + Assert.Equal (15, col); + Assert.Equal (4, row); + Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry)); + Assert.Equal (15, rx); + Assert.Equal (4, ry); + } + + [Fact, AutoInitShutdown] + public void ScreenToView_ViewToScreen_FindDeepestView_Smaller_Top () + { + var top = new Toplevel () { X = 3, Y = 2, Width = 20, Height = 10, BorderStyle = LineStyle.Single }; + var view = new View () { X = 3, Y = 2, Width = 10, Height = 1, Text = "0123456789" }; + top.Add (view); + + Application.Begin (top); + + Assert.Equal (Application.Top, top); + Assert.Equal (new Rect (0, 0, 80, 25), View.DriverFrame); + Assert.NotEqual (View.DriverFrame, top.Frame); + Assert.Equal (new Rect (3, 2, 20, 10), top.Frame); + Assert.Equal ((new (3, 2), new Point (-57, -13)), View.DriverFrameOffset); + + ((FakeDriver)Application.Driver).SetBufferSize (30, 20); + Assert.Equal (new Rect (0, 0, 30, 20), View.DriverFrame); + Assert.NotEqual (View.DriverFrame, top.Frame); + Assert.Equal (new Rect (3, 2, 20, 10), top.Frame); + Assert.Equal ((new (3, 2), new Point (-7, -8)), View.DriverFrameOffset); + var frame = TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌──────────────────┐ + │ │ + │ │ + │ 0123456789 │ + │ │ + │ │ + │ │ + │ │ + │ │ + └──────────────────┘", output); + // mean the output started at col 3 and line 2 + // which result with a width of 23 and a height of 10 on the output + Assert.Equal (new Rect (3, 2, 23, 10), frame); + + // top + Assert.Equal (new Point (-3, -2), top.ScreenToView (0, 0)); + top.Margin.ViewToScreen (-3, -2, out int col, out int row); + Assert.Equal (0, col); + Assert.Equal (0, row); + top.Border.ViewToScreen (-3, -2, out col, out row); + Assert.Equal (0, col); + Assert.Equal (0, row); + top.Padding.ViewToScreen (-3, -2, out col, out row); + Assert.Equal (0, col); + Assert.Equal (0, row); + top.ViewToScreen (-3, -2, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + top.ViewToScreen (-4, -3, out col, out row); + Assert.Equal (0, col); + Assert.Equal (0, row); + Assert.Null (View.FindDeepestView (top, -4, -3, out int rx, out int ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); + Assert.Equal (Point.Empty, top.ScreenToView (3, 2)); + top.ViewToScreen (0, 0, out col, out row); + Assert.Equal (4, col); + Assert.Equal (3, row); + Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); + Assert.Equal (new Point (10, 0), top.ScreenToView (13, 2)); + top.ViewToScreen (10, 0, out col, out row); + Assert.Equal (14, col); + Assert.Equal (3, row); + Assert.Equal (top, View.FindDeepestView (top, 13, 2, out rx, out ry)); + Assert.Equal (10, rx); + Assert.Equal (0, ry); + Assert.Equal (new Point (11, 1), top.ScreenToView (14, 3)); + top.ViewToScreen (11, 1, out col, out row); + Assert.Equal (15, col); + Assert.Equal (4, row); + Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry)); + Assert.Equal (11, rx); + Assert.Equal (1, ry); + // view + Assert.Equal (new Point (-6, -4), view.ScreenToView (0, 0)); + view.Margin.ViewToScreen (-6, -4, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + view.Border.ViewToScreen (-6, -4, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + view.Padding.ViewToScreen (-6, -4, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + view.ViewToScreen (-6, -4, out col, out row); + Assert.Equal (1, col); + Assert.Equal (1, row); + Assert.Null (View.FindDeepestView (top, 1, 1, out rx, out ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); + Assert.Equal (new Point (-3, -2), view.ScreenToView (3, 2)); + view.ViewToScreen (-3, -2, out col, out row); + Assert.Equal (4, col); + Assert.Equal (3, row); + Assert.Equal (top, View.FindDeepestView (top, 4, 3, out rx, out ry)); + Assert.Equal (1, rx); + Assert.Equal (1, ry); + Assert.Equal (Point.Empty, view.ScreenToView (6, 4)); + view.ViewToScreen (0, 0, out col, out row); + Assert.Equal (7, col); + Assert.Equal (5, row); + Assert.Equal (view, View.FindDeepestView (top, 7, 5, out rx, out ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); + Assert.Equal (new Point (7, 0), view.ScreenToView (13, 4)); + view.ViewToScreen (7, 0, out col, out row); + Assert.Equal (14, col); + Assert.Equal (5, row); + Assert.Equal (view, View.FindDeepestView (top, 14, 5, out rx, out ry)); + Assert.Equal (7, rx); + Assert.Equal (0, ry); + Assert.Equal (new Point (8, -1), view.ScreenToView (14, 3)); + view.ViewToScreen (8, -1, out col, out row); + Assert.Equal (15, col); + Assert.Equal (4, row); + Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry)); + Assert.Equal (12, rx); + Assert.Equal (2, ry); + Assert.Equal (new Point (17, -1), view.ScreenToView (23, 3)); + view.ViewToScreen (17, -1, out col, out row); + Assert.Equal (24, col); + Assert.Equal (4, row); + Assert.Null (View.FindDeepestView (top, 24, 4, out rx, out ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); + } } } diff --git a/UnitTests/Views/ContextMenuTests.cs b/UnitTests/Views/ContextMenuTests.cs index af2e16a838..e5bab36664 100644 --- a/UnitTests/Views/ContextMenuTests.cs +++ b/UnitTests/Views/ContextMenuTests.cs @@ -903,7 +903,6 @@ public void Key_Open_And_Close_The_ContextMenu () Assert.Null (tf.ContextMenu.MenuBar); } - // BUGBUG: Broke this test with #2483 - @bdisp I need your help figuring out why [Fact, AutoInitShutdown] public void Draw_A_ContextManu_Over_A_Dialog () { @@ -983,5 +982,51 @@ public void Draw_A_ContextManu_Over_A_Dialog () Application.End (rs); } + + [Fact, AutoInitShutdown] + public void Draw_A_ContextManu_Over_A_Top_Dialog () + { + ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + + Assert.Equal (new Rect (0, 0, 20, 15), Application.Driver.Clip); + TestHelpers.AssertDriverContentsWithFrameAre (@"", output); + + var dialog = new Dialog () { X = 2, Y = 2, Width = 15, Height = 4 }; + dialog.Add (new TextField ("Test") { X = Pos.Center (), Width = 10 }); + var rs = Application.Begin (dialog); + + Assert.Equal (new Rect (2, 2, 15, 4), dialog.Frame); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌─────────────┐ + │ Test │ + │ │ + └─────────────┘", output); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 9, + Y = 3, + Flags = MouseFlags.Button3Clicked + }); + + var firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌─────────────┐ + │ Test │ +┌─────────────────── +│ Select All Ctrl+ +│ Delete All Ctrl+ +│ Copy Ctrl+ +│ Cut Ctrl+ +│ Paste Ctrl+ +│ Undo Ctrl+ +│ Redo Ctrl+ +└───────────────────", output); + + Application.End (rs); + } } } diff --git a/UnitTests/Views/MenuTests.cs b/UnitTests/Views/MenuTests.cs index ab4e2d90d7..f4dfdc44c4 100644 --- a/UnitTests/Views/MenuTests.cs +++ b/UnitTests/Views/MenuTests.cs @@ -108,10 +108,10 @@ public void MenuOpening_MenuOpened_MenuClosing_Events () var cancelClosing = false; var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("_File", new MenuItem [] { - new MenuItem ("_New", "Creates new file.", New) - }) - }); + new MenuBarItem ("_File", new MenuItem [] { + new MenuItem ("_New", "Creates new file.", New) + }) + }); menu.MenuOpening += (s, e) => { Assert.Equal ("_File", e.CurrentMenu.Title); Assert.Equal ("_New", e.CurrentMenu.Children [0].Title); @@ -120,8 +120,8 @@ public void MenuOpening_MenuOpened_MenuClosing_Events () e.CurrentMenu.Children [0].Action (); Assert.Equal ("New", miAction); e.NewMenuBarItem = new MenuBarItem ("_Edit", new MenuItem [] { - new MenuItem ("_Copy", "Copies the selection.", Copy) - }); + new MenuItem ("_Copy", "Copies the selection.", Copy) + }); }; menu.MenuOpened += (s, e) => { var mi = e.MenuItem; @@ -190,14 +190,14 @@ public void MenuOpened_On_Disabled_MenuItem () Menu mCurrent = null; var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("_File", new MenuItem [] { - new MenuBarItem ("_New", new MenuItem [] { - new MenuItem ("_New doc", "Creates new doc.", null, () => false) - }), - null, - new MenuItem ("_Save", "Saves the file.", null, null) - }) - }); + new MenuBarItem ("_File", new MenuItem [] { + new MenuBarItem ("_New", new MenuItem [] { + new MenuItem ("_New doc", "Creates new doc.", null, () => false) + }), + null, + new MenuItem ("_Save", "Saves the file.", null, null) + }) + }); menu.MenuOpened += (s, e) => { miCurrent = e.MenuItem; mCurrent = menu.openMenu; @@ -283,17 +283,17 @@ public void MouseEvent_Test () MenuItem miCurrent = null; Menu mCurrent = null; var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("_File", new MenuItem [] { - new MenuItem ("_New", "", null), - new MenuItem ("_Open", "", null), - new MenuItem ("_Save", "", null) - }), - new MenuBarItem ("_Edit", new MenuItem [] { - new MenuItem ("_Copy", "", null), - new MenuItem ("C_ut", "", null), - new MenuItem ("_Paste", "", null) - }) - }); + new MenuBarItem ("_File", new MenuItem [] { + new MenuItem ("_New", "", null), + new MenuItem ("_Open", "", null), + new MenuItem ("_Save", "", null) + }), + new MenuBarItem ("_Edit", new MenuItem [] { + new MenuItem ("_Copy", "", null), + new MenuItem ("C_ut", "", null), + new MenuItem ("_Paste", "", null) + }) + }); menu.MenuOpened += (s, e) => { miCurrent = e.MenuItem; mCurrent = menu.openCurrentMenu; @@ -360,25 +360,25 @@ public void KeyBindings_Command () Menu mCurrent = null; var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("_File", new MenuItem [] { - new MenuItem ("_New", "", () => miAction ="New"), - new MenuItem ("_Open", "", () => miAction ="Open"), - new MenuItem ("_Save", "", () => miAction ="Save"), - null, - new MenuItem ("_Quit", "", () => miAction ="Quit"), - }), - new MenuBarItem ("_Edit", new MenuItem [] { - new MenuItem ("_Copy", "", () => miAction ="Copy"), - new MenuItem ("C_ut", "", () => miAction ="Cut"), - new MenuItem ("_Paste", "", () => miAction ="Paste"), - new MenuBarItem ("_Find and Replace", new MenuItem [] { - new MenuItem ("F_ind", "", null), - new MenuItem ("_Replace", "", null) - }), - new MenuItem ("_Select All", "", () => miAction ="Select All") - }), - new MenuBarItem ("_About", "Top-Level", () => miAction ="About") - }); + new MenuBarItem ("_File", new MenuItem [] { + new MenuItem ("_New", "", () => miAction ="New"), + new MenuItem ("_Open", "", () => miAction ="Open"), + new MenuItem ("_Save", "", () => miAction ="Save"), + null, + new MenuItem ("_Quit", "", () => miAction ="Quit"), + }), + new MenuBarItem ("_Edit", new MenuItem [] { + new MenuItem ("_Copy", "", () => miAction ="Copy"), + new MenuItem ("C_ut", "", () => miAction ="Cut"), + new MenuItem ("_Paste", "", () => miAction ="Paste"), + new MenuBarItem ("_Find and Replace", new MenuItem [] { + new MenuItem ("F_ind", "", null), + new MenuItem ("_Replace", "", null) + }), + new MenuItem ("_Select All", "", () => miAction ="Select All") + }), + new MenuBarItem ("_About", "Top-Level", () => miAction ="About") + }); menu.MenuOpening += (s, e) => mbiCurrent = e.CurrentMenu; menu.MenuOpened += (s, e) => { miCurrent = e.MenuItem; @@ -590,11 +590,11 @@ string GetCurrentMenuTitle () public void DrawFrame_With_Positive_Positions () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem (new MenuItem [] { - new MenuItem ("One", "", null), - new MenuItem ("Two", "", null) - }) - }); + new MenuBarItem (new MenuItem [] { + new MenuItem ("One", "", null), + new MenuItem ("Two", "", null) + }) + }); Assert.Equal (Point.Empty, new Point (menu.Frame.X, menu.Frame.Y)); @@ -616,11 +616,11 @@ public void DrawFrame_With_Positive_Positions () public void DrawFrame_With_Negative_Positions () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem (new MenuItem [] { - new MenuItem ("One", "", null), - new MenuItem ("Two", "", null) - }) - }) { + new MenuBarItem (new MenuItem [] { + new MenuItem ("One", "", null), + new MenuItem ("Two", "", null) + }) + }) { X = -1, Y = -1 }; @@ -690,15 +690,15 @@ public void DrawFrame_With_Negative_Positions () public void UseSubMenusSingleFrame_False_By_Keyboard () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }); + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }); menu.UseKeysUpDownAsKeysLeftRight = true; Application.Top.Add (menu); Application.Begin (Application.Top); @@ -766,15 +766,15 @@ public void UseSubMenusSingleFrame_False_By_Keyboard () public void UseSubMenusSingleFrame_False_By_Mouse () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }); + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -867,15 +867,15 @@ public void UseSubMenusSingleFrame_False_By_Mouse () public void UseSubMenusSingleFrame_True_By_Keyboard () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }); + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -951,15 +951,15 @@ public void UseSubMenusSingleFrame_True_By_Keyboard () public void UseSubMenusSingleFrame_True_By_Mouse () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }); + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1057,13 +1057,13 @@ public void HotKey_MenuBar_OnKeyDown_OnKeyUp_ProcessHotKey_ProcessKey () var copyAction = false; var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("_File", new MenuItem [] { - new MenuItem ("_New", "", () => newAction = true) - }), - new MenuBarItem ("_Edit", new MenuItem [] { - new MenuItem ("_Copy", "", () => copyAction = true) - }) - }); + new MenuBarItem ("_File", new MenuItem [] { + new MenuItem ("_New", "", () => newAction = true) + }), + new MenuBarItem ("_Edit", new MenuItem [] { + new MenuItem ("_Copy", "", () => copyAction = true) + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1157,12 +1157,12 @@ string padding (int i) // The fulll expected string for an open sub menu public string expectedSubMenuOpen (int i) => ClosedMenuText + - (Menus [i].Children.Length > 0 ? - padding (i) + expectedTopRow (i) + - padding (i) + expectedMenuItemRow (i) + - padding (i) + expectedBottomRow (i) - : - ""); + (Menus [i].Children.Length > 0 ? + padding (i) + expectedTopRow (i) + + padding (i) + expectedMenuItemRow (i) + + padding (i) + expectedBottomRow (i) + : + ""); public ExpectedMenuBar (MenuBarItem [] menus) : base (menus) { @@ -1174,33 +1174,33 @@ public void MenuBar_Submenus_Alignment_Correct () { // Define the expected menu var expectedMenu = new ExpectedMenuBar (new MenuBarItem [] { - new MenuBarItem ("File", new MenuItem [] { - new MenuItem ("Really Long Sub Menu", "", null) - }), - new MenuBarItem ("123", new MenuItem [] { - new MenuItem ("Copy", "", null) - }), - new MenuBarItem ("Format", new MenuItem [] { - new MenuItem ("Word Wrap", "", null) - }), - new MenuBarItem ("Help", new MenuItem [] { - new MenuItem ("About", "", null) - }), - new MenuBarItem ("1", new MenuItem [] { - new MenuItem ("2", "", null) - }), - new MenuBarItem ("3", new MenuItem [] { - new MenuItem ("2", "", null) - }), - new MenuBarItem ("Last one", new MenuItem [] { - new MenuItem ("Test", "", null) - }) - }); + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("Really Long Sub Menu", "", null) + }), + new MenuBarItem ("123", new MenuItem [] { + new MenuItem ("Copy", "", null) + }), + new MenuBarItem ("Format", new MenuItem [] { + new MenuItem ("Word Wrap", "", null) + }), + new MenuBarItem ("Help", new MenuItem [] { + new MenuItem ("About", "", null) + }), + new MenuBarItem ("1", new MenuItem [] { + new MenuItem ("2", "", null) + }), + new MenuBarItem ("3", new MenuItem [] { + new MenuItem ("2", "", null) + }), + new MenuBarItem ("Last one", new MenuItem [] { + new MenuItem ("Test", "", null) + }) + }); var items = new MenuBarItem [expectedMenu.Menus.Length]; for (var i = 0; i < expectedMenu.Menus.Length; i++) items [i] = new MenuBarItem (expectedMenu.Menus [i].Title, new MenuItem [] { - new MenuItem (expectedMenu.Menus [i].Children [0].Title, "", null) - }); + new MenuItem (expectedMenu.Menus [i].Children [0].Title, "", null) + }); var menu = new MenuBar (items); Application.Top.Add (menu); @@ -1225,23 +1225,23 @@ public void HotKey_MenuBar_ProcessHotKey_Menu_ProcessKey () // Define the expected menu var expectedMenu = new ExpectedMenuBar (new MenuBarItem [] { - new MenuBarItem ("File", new MenuItem [] { - new MenuItem ("New", "", null) - }), - new MenuBarItem ("Edit", new MenuItem [] { - new MenuItem ("Copy", "", null) - }) - }); + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("New", "", null) + }), + new MenuBarItem ("Edit", new MenuItem [] { + new MenuItem ("Copy", "", null) + }) + }); // The real menu var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("_" + expectedMenu.Menus[0].Title, new MenuItem [] { - new MenuItem ("_" + expectedMenu.Menus[0].Children[0].Title, "", () => newAction = true) - }), - new MenuBarItem ("_" + expectedMenu.Menus[1].Title, new MenuItem [] { - new MenuItem ("_" + expectedMenu.Menus[1].Children[0].Title, "", () => copyAction = true) - }), - }); + new MenuBarItem ("_" + expectedMenu.Menus[0].Title, new MenuItem [] { + new MenuItem ("_" + expectedMenu.Menus[0].Children[0].Title, "", () => newAction = true) + }), + new MenuBarItem ("_" + expectedMenu.Menus[1].Title, new MenuItem [] { + new MenuItem ("_" + expectedMenu.Menus[1].Children[0].Title, "", () => copyAction = true) + }), + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1273,23 +1273,23 @@ public void MenuBar_Position_And_Size_With_HotKeys_Is_The_Same_As_Without_HotKey { // Define the expected menu var expectedMenu = new ExpectedMenuBar (new MenuBarItem [] { - new MenuBarItem ("File", new MenuItem [] { - new MenuItem ("12", "", null) - }), - new MenuBarItem ("Edit", new MenuItem [] { - new MenuItem ("Copy", "", null) - }) - }); + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("12", "", null) + }), + new MenuBarItem ("Edit", new MenuItem [] { + new MenuItem ("Copy", "", null) + }) + }); // Test without HotKeys first var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem (expectedMenu.Menus[0].Title, new MenuItem [] { - new MenuItem (expectedMenu.Menus[0].Children[0].Title, "", null) - }), - new MenuBarItem (expectedMenu.Menus[1].Title, new MenuItem [] { - new MenuItem (expectedMenu.Menus[1].Children[0].Title, "", null) - }) - }); + new MenuBarItem (expectedMenu.Menus[0].Title, new MenuItem [] { + new MenuItem (expectedMenu.Menus[0].Children[0].Title, "", null) + }), + new MenuBarItem (expectedMenu.Menus[1].Title, new MenuItem [] { + new MenuItem (expectedMenu.Menus[1].Children[0].Title, "", null) + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1316,13 +1316,13 @@ public void MenuBar_Position_And_Size_With_HotKeys_Is_The_Same_As_Without_HotKey // Now test WITH HotKeys menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("_" + expectedMenu.Menus[0].Title, new MenuItem [] { - new MenuItem ("_" + expectedMenu.Menus[0].Children[0].Title, "", null) - }), - new MenuBarItem ("_" + expectedMenu.Menus[1].Title, new MenuItem [] { - new MenuItem ("_" + expectedMenu.Menus[1].Children[0].Title, "", null) - }), - }); + new MenuBarItem ("_" + expectedMenu.Menus[0].Title, new MenuItem [] { + new MenuItem ("_" + expectedMenu.Menus[0].Children[0].Title, "", null) + }), + new MenuBarItem ("_" + expectedMenu.Menus[1].Title, new MenuItem [] { + new MenuItem ("_" + expectedMenu.Menus[1].Children[0].Title, "", null) + }), + }); Application.Top.Add (menu); @@ -1350,23 +1350,23 @@ public void MenuBar_ButtonPressed_Open_The_Menu_ButtonPressed_Again_Close_The_Me { // Define the expected menu var expectedMenu = new ExpectedMenuBar (new MenuBarItem [] { - new MenuBarItem ("File", new MenuItem [] { - new MenuItem ("Open", "", null) - }), - new MenuBarItem ("Edit", new MenuItem [] { - new MenuItem ("Copy", "", null) - }) - }); + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("Open", "", null) + }), + new MenuBarItem ("Edit", new MenuItem [] { + new MenuItem ("Copy", "", null) + }) + }); // Test without HotKeys first var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("_" + expectedMenu.Menus[0].Title, new MenuItem [] { - new MenuItem ("_" + expectedMenu.Menus[0].Children[0].Title, "", null) - }), - new MenuBarItem ("_" + expectedMenu.Menus[1].Title, new MenuItem [] { - new MenuItem ("_" + expectedMenu.Menus[1].Children[0].Title, "", null) - }), - }); + new MenuBarItem ("_" + expectedMenu.Menus[0].Title, new MenuItem [] { + new MenuItem ("_" + expectedMenu.Menus[0].Children[0].Title, "", null) + }), + new MenuBarItem ("_" + expectedMenu.Menus[1].Title, new MenuItem [] { + new MenuItem ("_" + expectedMenu.Menus[1].Children[0].Title, "", null) + }), + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1409,24 +1409,24 @@ public void Parent_MenuItem_Stay_Focused_If_Child_MenuItem_Is_Empty_By_Mouse () // Define the expected menu var expectedMenu = new ExpectedMenuBar (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) - }) - }); + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("New", "", null) + }), + new MenuBarItem ("Edit", new MenuItem [] {}), + new MenuBarItem ("Format", new MenuItem [] { + new MenuItem ("Wrap", "", null) + }) + }); var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem (expectedMenu.Menus[0].Title, new MenuItem [] { - new MenuItem (expectedMenu.Menus[0].Children[0].Title, "", null) - }), - new MenuBarItem (expectedMenu.Menus[1].Title, new MenuItem [] {}), - new MenuBarItem (expectedMenu.Menus[2].Title, new MenuItem [] { - new MenuItem (expectedMenu.Menus[2].Children[0].Title, "", null) - }) - }); + new MenuBarItem (expectedMenu.Menus[0].Title, new MenuItem [] { + new MenuItem (expectedMenu.Menus[0].Children[0].Title, "", null) + }), + new MenuBarItem (expectedMenu.Menus[1].Title, new MenuItem [] {}), + new MenuBarItem (expectedMenu.Menus[2].Title, new MenuItem [] { + new MenuItem (expectedMenu.Menus[2].Children[0].Title, "", null) + }) + }); var tf = new TextField () { Y = 2, Width = 10 }; Application.Top.Add (menu, tf); @@ -1474,21 +1474,21 @@ public void Parent_MenuItem_Stay_Focused_If_Child_MenuItem_Is_Empty_By_Mouse () public void Parent_MenuItem_Stay_Focused_If_Child_MenuItem_Is_Empty_By_Keyboard () { var expectedMenu = new ExpectedMenuBar (new MenuBarItem [] { - new MenuBarItem ("File", new MenuItem [] { - new MenuItem ("New", "", null) - }), - new MenuBarItem ("Edit", Array.Empty ()), - new MenuBarItem ("Format", new MenuItem [] { - new MenuItem ("Wrap", "", null) - }) - }); + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("New", "", null) + }), + new MenuBarItem ("Edit", Array.Empty ()), + new MenuBarItem ("Format", new MenuItem [] { + new MenuItem ("Wrap", "", null) + }) + }); var items = new MenuBarItem [expectedMenu.Menus.Length]; for (var i = 0; i < expectedMenu.Menus.Length; i++) items [i] = new MenuBarItem (expectedMenu.Menus [i].Title, expectedMenu.Menus [i].Children.Length > 0 - ? new MenuItem [] { - new MenuItem (expectedMenu.Menus [i].Children [0].Title, "", null), - } - : Array.Empty ()); + ? new MenuItem [] { + new MenuItem (expectedMenu.Menus [i].Children [0].Title, "", null), + } + : Array.Empty ()); var menu = new MenuBar (items); var tf = new TextField () { Y = 2, Width = 10 }; @@ -1540,10 +1540,10 @@ public void Parent_MenuItem_Stay_Focused_If_Child_MenuItem_Is_Empty_By_Keyboard public void Key_Open_And_Close_The_MenuBar () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("File", new MenuItem [] { - new MenuItem ("New", "", null) - }) - }); + new MenuBarItem ("File", new MenuItem [] { + new MenuItem ("New", "", null) + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1566,13 +1566,13 @@ public void Key_Open_And_Close_The_MenuBar () public void Disabled_MenuItem_Is_Never_Selected () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Menu", new MenuItem [] { - new MenuItem ("Enabled 1", "", null), - new MenuItem ("Disabled", "", null, () => false), - null, - new MenuItem ("Enabled 2", "", null) - }) - }); + new MenuBarItem ("Menu", new MenuItem [] { + new MenuItem ("Enabled 1", "", null), + new MenuItem ("Disabled", "", null, () => false), + null, + new MenuItem ("Enabled 2", "", null) + }) + }); var top = Application.Top; top.Add (menu); @@ -1585,7 +1585,7 @@ public void Disabled_MenuItem_Is_Never_Selected () menu.ColorScheme.Focus, // 2 menu.ColorScheme.Disabled - }; + }; TestHelpers.AssertDriverColorsAre (@" 00000000000000", attributes); @@ -1658,7 +1658,93 @@ public void MenuBar_With_Action_But_Without_MenuItems_Not_Throw () } [Fact, AutoInitShutdown] - public void MenuBar_In_Window_Without_Other_Views () + public void MenuBar_In_Window_Without_Other_Views_With_Top_Init_With_Parameterless_Run () + { + 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.Iteration += () => { + ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (win.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + top.Redraw (top.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│┌──────┐ │ +││ New │ │ +│└──────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + Application.Refresh (); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│ │ +│ └─────────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + top.Redraw (top.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│┌───────────┐ │ +│ └─────────┘│ All │ │ +│ │ Selected │ │ +│ └───────────┘ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + top.Redraw (top.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│┌──────┐ │ +││ New │ │ +│└──────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Application.RequestStop (); + }; + + Application.Run (); + } + + [Fact, AutoInitShutdown] + public void MenuBar_In_Window_Without_Other_Views_With_Top_Init () { var win = new Window (); var menu = new MenuBar (new MenuBarItem [] { @@ -1671,7 +1757,7 @@ public void MenuBar_In_Window_Without_Other_Views () new MenuItem ("Selected", "", null) }) }) - }); ; + }); win.Add (menu); var top = Application.Top; top.Add (win); @@ -1737,6 +1823,174 @@ public void MenuBar_In_Window_Without_Other_Views () └──────────────────────────────────────┘", output); } + [Fact, AutoInitShutdown] + public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init () + { + 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); + ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + Application.Begin (win); + + 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 ()))); + Application.Refresh (); + 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); + } + + [Fact, AutoInitShutdown] + public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () + { + ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + + Application.Iteration += () => { + var top = Application.Top; + + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (top.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + top.Redraw (top.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│┌──────┐ │ +││ New │ │ +│└──────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (top.Subviews [0].ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + Application.Refresh (); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│ │ +│ └─────────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (((MenuBar)top.Subviews [0]).openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + top.Redraw (top.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│┌───────────┐ │ +│ └─────────┘│ All │ │ +│ │ Selected │ │ +│ └───────────┘ │ +└──────────────────────────────────────┘", output); + + Assert.True (((MenuBar)top.Subviews [0]).openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + top.Redraw (top.Bounds); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│┌──────┐ │ +││ New │ │ +│└──────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Application.RequestStop (); + }; + + Application.Run (); + } + + private class CustomWindow : Window { + public CustomWindow () + { + 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) + }) + }) + }); + Add (menu); + } + } + [Fact, AutoInitShutdown] public void AllowNullChecked_Get_Set () { @@ -1745,10 +1999,10 @@ public void AllowNullChecked_Get_Set () }; mi.Action = mi.ToggleChecked; var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem("Nullable Checked",new MenuItem [] { - mi - }) - }); + new MenuBarItem("Nullable Checked",new MenuItem [] { + mi + }) + }); new CheckBox (); var top = Application.Top; top.Add (menu); @@ -1832,12 +2086,12 @@ Nullable Checked public void Menu_With_Separator () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem("File",new MenuItem [] { - new MenuItem("_Open", "Open a file", () => { }, null, null, Key.CtrlMask | Key.O), - null, - new MenuItem("_Quit","",null) - }) - }); + new MenuBarItem("File",new MenuItem [] { + new MenuItem("_Open", "Open a file", () => { }, null, null, Key.CtrlMask | Key.O), + null, + new MenuItem("_Quit","",null) + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1857,12 +2111,12 @@ public void Menu_With_Separator () public void Menu_With_Separator_Disabled_Border () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem("File",new MenuItem [] { - new MenuItem("_Open", "Open a file", () => { }, null, null, Key.CtrlMask | Key.O), - null, - new MenuItem("_Quit","",null) - }) - }) { MenusBorderStyle = LineStyle.None }; + new MenuBarItem("File",new MenuItem [] { + new MenuItem("_Open", "Open a file", () => { }, null, null, Key.CtrlMask | Key.O), + null, + new MenuItem("_Quit","",null) + }) + }) { MenusBorderStyle = LineStyle.None }; Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1880,11 +2134,11 @@ Open Open a file Ctrl+O public void DrawFrame_With_Positive_Positions_Disabled_Border () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem (new MenuItem [] { - new MenuItem ("One", "", null), - new MenuItem ("Two", "", null) - }) - }) { MenusBorderStyle = LineStyle.None }; + new MenuBarItem (new MenuItem [] { + new MenuItem ("One", "", null), + new MenuItem ("Two", "", null) + }) + }) { MenusBorderStyle = LineStyle.None }; Assert.Equal (Point.Empty, new Point (menu.Frame.X, menu.Frame.Y)); @@ -1903,11 +2157,11 @@ public void DrawFrame_With_Positive_Positions_Disabled_Border () public void DrawFrame_With_Negative_Positions_Disabled_Border () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem (new MenuItem [] { - new MenuItem ("One", "", null), - new MenuItem ("Two", "", null) - }) - }) { + new MenuBarItem (new MenuItem [] { + new MenuItem ("One", "", null), + new MenuItem ("Two", "", null) + }) + }) { X = -2, Y = -1, MenusBorderStyle = LineStyle.None @@ -1956,7 +2210,7 @@ public void DrawFrame_With_Negative_Positions_Disabled_Border () Application.Refresh (); expected = @" - Tw + On "; _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); @@ -1966,15 +2220,15 @@ public void DrawFrame_With_Negative_Positions_Disabled_Border () public void UseSubMenusSingleFrame_False_Disabled_Border () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }) { MenusBorderStyle = LineStyle.None }; + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }) { MenusBorderStyle = LineStyle.None }; menu.UseKeysUpDownAsKeysLeftRight = true; Application.Top.Add (menu); Application.Begin (Application.Top); @@ -2009,15 +2263,15 @@ Three Sub-Menu 2 public void UseSubMenusSingleFrame_True_Disabled_Border () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }) { MenusBorderStyle = LineStyle.None }; + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }) { MenusBorderStyle = LineStyle.None }; Application.Top.Add (menu); Application.Begin (Application.Top); From 82beaa194f54984a93a19e25ac87d167979430ad Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 24 Apr 2023 01:37:14 +0100 Subject: [PATCH 02/16] Replacing Application.Top with Application.Current. --- Terminal.Gui/View/View.cs | 21 ++++++++++++---- Terminal.Gui/Views/ContextMenu.cs | 4 ++-- Terminal.Gui/Views/Menu.cs | 40 +++++++++++++++++++------------ UnitTests/View/NavigationTests.cs | 7 +++--- 4 files changed, 46 insertions(+), 26 deletions(-) diff --git a/Terminal.Gui/View/View.cs b/Terminal.Gui/View/View.cs index 977d24fddb..01ccd25225 100644 --- a/Terminal.Gui/View/View.cs +++ b/Terminal.Gui/View/View.cs @@ -523,14 +523,25 @@ protected override void Dispose (bool disposing) /// /// Gets the superview location offset relative to the . /// - /// - /// The location offset and the respective superview. - public Point GetDriverLocationOffset (View superView) + /// The location offset. + public Point GetDriverLocationOffset () { - var superViewFrame = superView == null || (superView == Application.Top && SuperView != superView) ? DriverFrame : superView.Frame; - var sv = superView == null ? Application.Top : superView; + var superViewFrame = SuperView == null ? DriverFrame : SuperView.Frame; + var sv = SuperView == null ? Application.Current : SuperView; return new Point (superViewFrame.X - sv.Frame.X - (superViewFrame.X != sv.Frame.X ? 1 : 0), superViewFrame.Y - sv.Frame.Y - (superViewFrame.Y != sv.Frame.Y ? 1 : 0)); } + + /// + /// Gets the location offset relative to the . + /// + /// The location offset. + public Point GetDriverLocationOffsetFromCurrent () + { + var topFrame = DriverFrame; + var currentFrame = Application.Current.Frame; + return new Point (topFrame.X - currentFrame.X - (topFrame.X != currentFrame.X ? 1 : 0), + topFrame.Y - currentFrame.Y - (topFrame.Y != currentFrame.Y ? 1 : 0)); + } } } diff --git a/Terminal.Gui/Views/ContextMenu.cs b/Terminal.Gui/Views/ContextMenu.cs index 64ebf719e8..0f1d68410f 100644 --- a/Terminal.Gui/Views/ContextMenu.cs +++ b/Terminal.Gui/Views/ContextMenu.cs @@ -33,7 +33,7 @@ public sealed class ContextMenu : IDisposable { public ContextMenu () : this (0, 0, new MenuBarItem ()) { } /// - /// Initializes a context menu, with a specifiying the parent/hose of the menu. + /// Initializes a context menu, with a specifying the parent/host of the menu. /// /// The host view. /// The menu items for the context menu. @@ -91,7 +91,7 @@ public void Show () if (menuBar != null) { Hide (); } - container = Application.Top; + container = Application.Current; container.Closing += Container_Closing; container.TerminalResized += Container_Resized; var frame = View.DriverFrame; diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 34d0da8393..465a2be174 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -482,6 +482,7 @@ public Menu (MenuBar host, int x, int y, MenuBarItem barItems, Menu parent = nul if (Application.Current != null) { Application.Current.DrawContentComplete += Current_DrawContentComplete; + Application.Current.TerminalResized += Current_TerminalResized; } Application.RootMouseEvent += Application_RootMouseEvent; @@ -510,13 +511,21 @@ public Menu (MenuBar host, int x, int y, MenuBarItem barItems, Menu parent = nul AddKeyBinding (Key.Enter, Command.Accept); } + private void Current_TerminalResized (object sender, SizeChangedEventArgs e) + { + if (host.IsMenuOpen) { + host.CloseMenu (false); + host.OpenMenu (); + } + } + private void Application_RootMouseEvent (MouseEvent me) { if (me.View is MenuBar) { return; } - var locationOffset = GetDriverLocationOffset (null); - if (SuperView != null) { + var locationOffset = GetDriverLocationOffsetFromCurrent (); + if (SuperView != null && SuperView != Application.Current) { locationOffset.X += SuperView.Border.Thickness.Left; locationOffset.Y += SuperView.Border.Thickness.Top; } @@ -870,8 +879,8 @@ public override bool MouseEvent (MouseEvent me) } host.handled = false; bool disabled; - Point locationOffset = default; - if (SuperView != null) { + Point locationOffset = GetDriverLocationOffset (); + if (SuperView != null && SuperView != Application.Current) { locationOffset.X += SuperView.Border.Thickness.Left; locationOffset.Y += SuperView.Border.Thickness.Top; } @@ -967,6 +976,7 @@ protected override void Dispose (bool disposing) { if (Application.Current != null) { Application.Current.DrawContentComplete -= Current_DrawContentComplete; + Application.Current.TerminalResized -= Current_TerminalResized; } Application.RootMouseEvent -= Application_RootMouseEvent; base.Dispose (disposing); @@ -1398,7 +1408,7 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem subMenu = null) if (openSubMenu != null && !CloseMenu (false, true)) return; if (openMenu != null) { - Application.Top.Remove (openMenu); + Application.Current.Remove (openMenu); openMenu.Dispose (); openMenu = null; } @@ -1408,17 +1418,17 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem subMenu = null) for (int i = 0; i < index; i++) pos += Menus [i].TitleLength + (Menus [i].Help.ConsoleWidth > 0 ? Menus [i].Help.ConsoleWidth + 2 : 0) + leftPadding + rightPadding; - var superView = SuperView == null ? Application.Top : SuperView; - var locationOffset = GetDriverLocationOffset (superView); - if (superView != Application.Top) { - locationOffset.X += superView.Border.Thickness.Left; - locationOffset.Y += superView.Border.Thickness.Top; + var locationOffset = GetDriverLocationOffset (); + // if SuperView is null then it's from a ContextMenu + if (SuperView != null && SuperView != Application.Current) { + locationOffset.X += SuperView.Border.Thickness.Left; + locationOffset.Y += SuperView.Border.Thickness.Top; } openMenu = new Menu (this, Frame.X + pos + locationOffset.X, Frame.Y + 1 + locationOffset.Y, Menus [index], null, MenusBorderStyle); openCurrentMenu = openMenu; openCurrentMenu.previousSubFocused = openMenu; - Application.Top.Add (openMenu); + Application.Current.Add (openMenu); openMenu.SetFocus (); break; default: @@ -1448,7 +1458,7 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem subMenu = null) } openCurrentMenu.previousSubFocused = last.previousSubFocused; openSubMenu.Add (openCurrentMenu); - Application.Top.Add (openCurrentMenu); + Application.Current.Add (openCurrentMenu); } selectedSub = openSubMenu.Count - 1; if (selectedSub > -1 && SelectEnabledItem (openCurrentMenu.barItems.Children, openCurrentMenu.current, out openCurrentMenu.current)) { @@ -1579,7 +1589,7 @@ internal bool CloseMenu (bool reopen = false, bool isSubMenu = false, bool ignor switch (isSubMenu) { case false: if (openMenu != null) { - Application.Top.Remove (openMenu); + Application.Current.Remove (openMenu); } SetNeedsDisplay (); if (previousFocused != null && previousFocused is Menu && openMenu != null && previousFocused.ToString () != openCurrentMenu.ToString ()) @@ -1638,7 +1648,7 @@ void RemoveSubMenu (int index, bool ignoreUseSubMenusSingleFrame = false) openCurrentMenu.SetFocus (); if (openSubMenu != null) { menu = openSubMenu [i]; - Application.Top.Remove (menu); + Application.Current.Remove (menu); openSubMenu.Remove (menu); menu.Dispose (); } @@ -1654,7 +1664,7 @@ internal void RemoveAllOpensSubMenus () { if (openSubMenu != null) { foreach (var item in openSubMenu) { - Application.Top.Remove (item); + Application.Current.Remove (item); item.Dispose (); } } diff --git a/UnitTests/View/NavigationTests.cs b/UnitTests/View/NavigationTests.cs index aed45485bf..3c3edb6c38 100644 --- a/UnitTests/View/NavigationTests.cs +++ b/UnitTests/View/NavigationTests.cs @@ -1079,18 +1079,17 @@ public void FocusNext_Does_Not_Throws_If_A_View_Was_Removed_From_The_Collection Assert.Null (view3); } - [Fact, AutoInitShutdown] public void ScreenToView_ViewToScreen_FindDeepestView_Full_Top () { - var top = Application.Top; + var top = Application.Current; top.BorderStyle = LineStyle.Single; var view = new View () { X = 3, Y = 2, Width = 10, Height = 1, Text = "0123456789" }; top.Add (view); Application.Begin (top); - Assert.Equal (Application.Top, top); + Assert.Equal (Application.Current, top); Assert.Equal (new Rect (0, 0, 80, 25), View.DriverFrame); Assert.Equal (View.DriverFrame, top.Frame); Assert.Equal (new Rect (0, 0, 80, 25), top.Frame); @@ -1205,7 +1204,7 @@ public void ScreenToView_ViewToScreen_FindDeepestView_Smaller_Top () Application.Begin (top); - Assert.Equal (Application.Top, top); + Assert.Equal (Application.Current, top); Assert.Equal (new Rect (0, 0, 80, 25), View.DriverFrame); Assert.NotEqual (View.DriverFrame, top.Frame); Assert.Equal (new Rect (3, 2, 20, 10), top.Frame); From 80410bae0264ca4c39c8e6295d92ae6cc062f960 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 24 Apr 2023 12:28:25 +0100 Subject: [PATCH 03/16] Fix typo. --- UnitTests/Views/ContextMenuTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UnitTests/Views/ContextMenuTests.cs b/UnitTests/Views/ContextMenuTests.cs index e5bab36664..427e42255c 100644 --- a/UnitTests/Views/ContextMenuTests.cs +++ b/UnitTests/Views/ContextMenuTests.cs @@ -904,7 +904,7 @@ public void Key_Open_And_Close_The_ContextMenu () } [Fact, AutoInitShutdown] - public void Draw_A_ContextManu_Over_A_Dialog () + public void Draw_A_ContextMenu_Over_A_Dialog () { var top = Application.Top; var win = new Window (); @@ -984,7 +984,7 @@ public void Draw_A_ContextManu_Over_A_Dialog () } [Fact, AutoInitShutdown] - public void Draw_A_ContextManu_Over_A_Top_Dialog () + public void Draw_A_ContextMenu_Over_A_Top_Dialog () { ((FakeDriver)Application.Driver).SetBufferSize (20, 15); From f759b27fbfb107faf74cef0721bf813278254d95 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 24 Apr 2023 18:26:36 +0100 Subject: [PATCH 04/16] Fix shortcut tag overlapping help on smaller width and add more unit test. --- Terminal.Gui/Views/Menu.cs | 17 ++- UnitTests/Views/MenuTests.cs | 267 +++++++++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+), 7 deletions(-) diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 465a2be174..67b90cf547 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -584,8 +584,12 @@ public override void Redraw (Rect bounds) Driver.SetAttribute (DetermineColorSchemeFor (item, i)); for (int p = Bounds.X; p < Frame.Width - 2; p++) { // This - 2 is for the border - if (p < 0) + if (p < 0) { continue; + } + if (ViewToScreen (Bounds).X + p >= Driver.Cols) { + break; + } if (item == null) Driver.AddRune (Driver.HLine); else if (i == 0 && p == 0 && host.UseSubMenusSingleFrame && item.Parent.Parent != null) @@ -626,9 +630,9 @@ public override void Redraw (Rect bounds) textToDraw = item.Title; } - ViewToScreen (0, i, out int vtsCol, out _, false); + ViewToScreen (0, i, out int vtsCol, out int vtsRow, false); if (vtsCol < Driver.Cols) { - Move (1, i); + Driver.Move (vtsCol + 1, vtsRow); if (!item.IsEnabled ()) { DrawHotString (textToDraw, ColorScheme.Disabled, ColorScheme.Disabled); } else if (i == 0 && host.UseSubMenusSingleFrame && item.Parent.Parent != null) { @@ -651,15 +655,14 @@ public override void Redraw (Rect bounds) // The help string var l = item.ShortcutTag.ConsoleWidth == 0 ? item.Help.ConsoleWidth : item.Help.ConsoleWidth + item.ShortcutTag.ConsoleWidth + 2; var col = Frame.Width - l - 3; - ViewToScreen (col, i, out vtsCol, out _, false); + ViewToScreen (col, i, out vtsCol, out vtsRow, false); if (vtsCol < Driver.Cols) { - Move (col, i); + Driver.Move (vtsCol, vtsRow); Driver.AddStr (item.Help); // The shortcut tag string if (!item.ShortcutTag.IsEmpty) { - l = item.ShortcutTag.ConsoleWidth; - Move (Frame.Width - l - 3, i); + Driver.Move (vtsCol + l - item.ShortcutTag.ConsoleWidth, vtsRow); Driver.AddStr (item.ShortcutTag); } } diff --git a/UnitTests/Views/MenuTests.cs b/UnitTests/Views/MenuTests.cs index f4dfdc44c4..51f803962f 100644 --- a/UnitTests/Views/MenuTests.cs +++ b/UnitTests/Views/MenuTests.cs @@ -2306,5 +2306,272 @@ public void UseSubMenusSingleFrame_True_Disabled_Border () _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); } + + [Fact, AutoInitShutdown] + public void Draw_A_Menu_Over_A_Dialog () + { + var top = Application.Top; + var win = new Window (); + top.Add (win); + Application.Begin (top); + ((FakeDriver)Application.Driver).SetBufferSize (40, 15); + + Assert.Equal (new Rect (0, 0, 40, 15), win.Frame); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + var items = new List { "New", "Open", "Close", "Save", "Save As", "Delete" }; + var dialog = new Dialog () { X = 2, Y = 2, Width = 15, Height = 4 }; + var menu = new MenuBar () { X = Pos.Center (), Width = 10 }; + menu.Menus = new MenuBarItem [] { + new MenuBarItem("File", new MenuItem [] { + new MenuItem(items[0], "Create a new file", () => ChangeMenuTitle("New"),null,null, Key.CtrlMask | Key.N), + new MenuItem(items[1], "Open a file", () => ChangeMenuTitle("Open"),null,null, Key.CtrlMask | Key.O), + new MenuItem(items[2], "Close a file", () => ChangeMenuTitle("Close"),null,null, Key.CtrlMask | Key.C), + new MenuItem(items[3], "Save a file", () => ChangeMenuTitle("Save"),null,null, Key.CtrlMask | Key.S), + new MenuItem(items[4], "Save a file as", () => ChangeMenuTitle("Save As"),null,null, Key.CtrlMask | Key.A), + new MenuItem(items[5], "Delete a file", () => ChangeMenuTitle("Delete"),null,null, Key.CtrlMask | Key.A), + }) + }; + dialog.Add (menu); + + void ChangeMenuTitle (string title) + { + menu.Menus [0].Title = title; + menu.SetNeedsDisplay (); + } + + var rs = Application.Begin (dialog); + + Assert.Equal (new Rect (2, 2, 15, 4), dialog.Frame); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ │ +│ ┌─────────────┐ │ +│ │ File │ │ +│ │ │ │ +│ └─────────────┘ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.Equal ("File", menu.Menus [0].Title); + menu.OpenMenu (); + var firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ │ +│ ┌─────────────┐ │ +│ │ File │ │ +│ │ ┌──────────────────────────────────┐ +│ └─│ New Create a new file Ctrl+N │ +│ │ Open Open a file Ctrl+O │ +│ │ Close Close a file Ctrl+C │ +│ │ Save Save a file Ctrl+S │ +│ │ Save As Save a file as Ctrl+A │ +│ │ Delete Delete a file Ctrl+A │ +│ └──────────────────────────────────┘ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 20, + Y = 5, + Flags = MouseFlags.Button1Clicked + }); + + firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + Assert.Equal (items [0], menu.Menus [0].Title); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ │ +│ ┌─────────────┐ │ +│ │ New │ │ +│ │ │ │ +│ └─────────────┘ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + for (int i = 1; i < items.Count; i++) { + menu.OpenMenu (); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 20, + Y = 5 + i, + Flags = MouseFlags.Button1Clicked + }); + + firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + Assert.Equal (items [i], menu.Menus [0].Title); + } + + ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + menu.OpenMenu (); + firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────┐ +│ │ +│ ┌─────────────┐ │ +│ │ Delete │ │ +│ │ ┌─────────────── +│ └─│ New Create +│ │ Open O +│ │ Close Cl +│ │ Save S +│ │ Save As Save +│ │ Delete Del +│ └─────────────── +│ │ +│ │ +└──────────────────┘", output); + + Application.End (rs); + } + + [Fact, AutoInitShutdown] + public void Draw_A_Menu_Over_A_Top_Dialog () + { + ((FakeDriver)Application.Driver).SetBufferSize (40, 15); + + Assert.Equal (new Rect (0, 0, 40, 15), Application.Driver.Clip); + TestHelpers.AssertDriverContentsWithFrameAre (@"", output); + + var items = new List { "New", "Open", "Close", "Save", "Save As", "Delete" }; + var dialog = new Dialog () { X = 2, Y = 2, Width = 15, Height = 4 }; + var menu = new MenuBar () { X = Pos.Center (), Width = 10 }; + menu.Menus = new MenuBarItem [] { + new MenuBarItem("File", new MenuItem [] { + new MenuItem(items[0], "Create a new file", () => ChangeMenuTitle("New"),null,null, Key.CtrlMask | Key.N), + new MenuItem(items[1], "Open a file", () => ChangeMenuTitle("Open"),null,null, Key.CtrlMask | Key.O), + new MenuItem(items[2], "Close a file", () => ChangeMenuTitle("Close"),null,null, Key.CtrlMask | Key.C), + new MenuItem(items[3], "Save a file", () => ChangeMenuTitle("Save"),null,null, Key.CtrlMask | Key.S), + new MenuItem(items[4], "Save a file as", () => ChangeMenuTitle("Save As"),null,null, Key.CtrlMask | Key.A), + new MenuItem(items[5], "Delete a file", () => ChangeMenuTitle("Delete"),null,null, Key.CtrlMask | Key.A), + }) + }; + dialog.Add (menu); + + void ChangeMenuTitle (string title) + { + menu.Menus [0].Title = title; + menu.SetNeedsDisplay (); + } + + var rs = Application.Begin (dialog); + + Assert.Equal (new Rect (2, 2, 15, 4), dialog.Frame); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌─────────────┐ + │ File │ + │ │ + └─────────────┘", output); + + Assert.Equal ("File", menu.Menus [0].Title); + menu.OpenMenu (); + var firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌─────────────┐ + │ File │ + │ ┌──────────────────────────────────┐ + └─│ New Create a new file Ctrl+N │ + │ Open Open a file Ctrl+O │ + │ Close Close a file Ctrl+C │ + │ Save Save a file Ctrl+S │ + │ Save As Save a file as Ctrl+A │ + │ Delete Delete a file Ctrl+A │ + └──────────────────────────────────┘", output); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 20, + Y = 5, + Flags = MouseFlags.Button1Clicked + }); + + firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + Assert.Equal (items [0], menu.Menus [0].Title); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌─────────────┐ + │ New │ + │ │ + └─────────────┘", output); + + for (int i = 1; i < items.Count; i++) { + menu.OpenMenu (); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 20, + Y = 5 + i, + Flags = MouseFlags.Button1Clicked + }); + + firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + Assert.Equal (items [i], menu.Menus [0].Title); + } + + ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + menu.OpenMenu (); + firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌─────────────┐ + │ Delete │ + │ ┌─────────────── + └─│ New Create + │ Open O + │ Close Cl + │ Save S + │ Save As Save + │ Delete Del + └───────────────", output); + + Application.End (rs); + } } } From fac62cca84b8abf80fa60ea0321c9033316373f5 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 24 Apr 2023 19:02:45 +0100 Subject: [PATCH 05/16] Resizing the console will close all opened menus. --- Terminal.Gui/Views/ContextMenu.cs | 9 --------- Terminal.Gui/Views/Menu.cs | 3 +-- UnitTests/Views/MenuTests.cs | 31 ++++++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Terminal.Gui/Views/ContextMenu.cs b/Terminal.Gui/Views/ContextMenu.cs index 0f1d68410f..6ddf55d222 100644 --- a/Terminal.Gui/Views/ContextMenu.cs +++ b/Terminal.Gui/Views/ContextMenu.cs @@ -79,7 +79,6 @@ public void Dispose () } if (container != null) { container.Closing -= Container_Closing; - container.TerminalResized -= Container_Resized; } } @@ -93,7 +92,6 @@ public void Show () } container = Application.Current; container.Closing += Container_Closing; - container.TerminalResized += Container_Resized; var frame = View.DriverFrame; var position = Position; if (Host != null) { @@ -145,13 +143,6 @@ public void Show () menuBar.OpenMenu (); } - private void Container_Resized (object sender, SizeChangedEventArgs e) - { - if (IsShow) { - Show (); - } - } - private void Container_Closing (object sender, ToplevelClosingEventArgs obj) { Hide (); diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 67b90cf547..1924b27676 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -514,8 +514,7 @@ public Menu (MenuBar host, int x, int y, MenuBarItem barItems, Menu parent = nul private void Current_TerminalResized (object sender, SizeChangedEventArgs e) { if (host.IsMenuOpen) { - host.CloseMenu (false); - host.OpenMenu (); + host.CloseAllMenus (); } } diff --git a/UnitTests/Views/MenuTests.cs b/UnitTests/Views/MenuTests.cs index 51f803962f..befbb7afbe 100644 --- a/UnitTests/Views/MenuTests.cs +++ b/UnitTests/Views/MenuTests.cs @@ -2555,7 +2555,7 @@ void ChangeMenuTitle (string title) Assert.Equal (items [i], menu.Menus [0].Title); } - ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + ((FakeDriver)Application.Driver).SetBufferSize (20, 15); menu.OpenMenu (); firstIteration = false; Application.RunMainLoopIteration (ref rs, true, ref firstIteration); @@ -2573,5 +2573,34 @@ void ChangeMenuTitle (string title) Application.End (rs); } + + [Fact, AutoInitShutdown] + public void Resizing_Close_Menus () + { + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem ("File", new MenuItem [] { + new MenuItem("Open", "Open a file", () => {},null,null, Key.CtrlMask | Key.O) + }) + }); + Application.Top.Add (menu); + var rs = Application.Begin (Application.Top); + + menu.OpenMenu (); + var firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" + File +┌────────────────────────────┐ +│ Open Open a file Ctrl+O │ +└────────────────────────────┘", output); + + ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" + File", output); + + Application.End (rs); + } } } From b362bb31dea08bfe215489b30f21ab7c93b7da71 Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 24 Apr 2023 19:13:47 +0100 Subject: [PATCH 06/16] Resize first the console before show ContextMenu. --- UnitTests/Views/ContextMenuTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/UnitTests/Views/ContextMenuTests.cs b/UnitTests/Views/ContextMenuTests.cs index 427e42255c..f6a5a522e2 100644 --- a/UnitTests/Views/ContextMenuTests.cs +++ b/UnitTests/Views/ContextMenuTests.cs @@ -380,6 +380,8 @@ public void Show_Display_Below_The_Bottom_Host_If_Has_Enough_Space () [Fact, AutoInitShutdown] public void Show_Display_At_Zero_If_The_Toplevel_Width_Is_Less_Than_The_Menu_Width () { + ((FakeDriver)Application.Driver).SetBufferSize (5, 25); + var cm = new ContextMenu (0, 0, new MenuBarItem (new MenuItem [] { new MenuItem ("One", "", null), @@ -392,14 +394,12 @@ public void Show_Display_At_Zero_If_The_Toplevel_Width_Is_Less_Than_The_Menu_Wid cm.Show (); Assert.Equal (new Point (0, 0), cm.Position); Application.Begin (Application.Top); - ((FakeDriver)Application.Driver).SetBufferSize (5, 25); var expected = @" ┌──── │ One │ Two -└──── -"; +└────"; var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); Assert.Equal (new Rect (0, 1, 5, 4), pos); @@ -411,6 +411,8 @@ public void Show_Display_At_Zero_If_The_Toplevel_Width_Is_Less_Than_The_Menu_Wid [Fact, AutoInitShutdown] public void Show_Display_At_Zero_If_The_Toplevel_Height_Is_Less_Than_The_Menu_Height () { + ((FakeDriver)Application.Driver).SetBufferSize (80, 3); + var cm = new ContextMenu (0, 0, new MenuBarItem (new MenuItem [] { new MenuItem ("One", "", null), @@ -423,13 +425,11 @@ public void Show_Display_At_Zero_If_The_Toplevel_Height_Is_Less_Than_The_Menu_He cm.Show (); Assert.Equal (new Point (0, 0), cm.Position); Application.Begin (Application.Top); - ((FakeDriver)Application.Driver).SetBufferSize (80, 3); var expected = @" ┌──────┐ │ One │ -│ Two │ -"; +│ Two │"; var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); Assert.Equal (new Rect (0, 0, 8, 3), pos); From d975a5747c5df974eabfa924ed1f2d7200890e99 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 29 Apr 2023 14:57:39 +0100 Subject: [PATCH 07/16] Remove DriverFrame and DriverFrameOffset as not relevant. --- Terminal.Gui/View/View.cs | 15 ++------------- Terminal.Gui/Views/ContextMenu.cs | 2 +- Terminal.Gui/Views/Menu.cs | 2 +- UnitTests/View/NavigationTests.cs | 18 +++++++----------- 4 files changed, 11 insertions(+), 26 deletions(-) diff --git a/Terminal.Gui/View/View.cs b/Terminal.Gui/View/View.cs index 01ccd25225..da121e2628 100644 --- a/Terminal.Gui/View/View.cs +++ b/Terminal.Gui/View/View.cs @@ -321,17 +321,6 @@ public void EndInit () /// public static ConsoleDriver Driver => Application.Driver; - /// - /// Gets the current driver in use by the view. - /// - public static Rect DriverFrame => new (0, 0, Driver.Cols, Driver.Rows); - - /// - /// Gets the current driver location and dimension in use by the view - /// offset by the location and dimension. - /// - public static (Point Location, Point Dimension) DriverFrameOffset => new (new Point (Application.Top.Frame.X, Application.Top.Frame.Y), new (Application.Top.Frame.X + Application.Top.Frame.Width - Driver.Cols, Application.Top.Frame.Y + Application.Top.Frame.Height - Driver.Rows)); - /// /// Gets or sets arbitrary data for the view. /// @@ -526,7 +515,7 @@ protected override void Dispose (bool disposing) /// The location offset. public Point GetDriverLocationOffset () { - var superViewFrame = SuperView == null ? DriverFrame : SuperView.Frame; + var superViewFrame = SuperView == null ? new Rect (0, 0, Driver.Cols, Driver.Rows) : SuperView.Frame; var sv = SuperView == null ? Application.Current : SuperView; return new Point (superViewFrame.X - sv.Frame.X - (superViewFrame.X != sv.Frame.X ? 1 : 0), superViewFrame.Y - sv.Frame.Y - (superViewFrame.Y != sv.Frame.Y ? 1 : 0)); @@ -538,7 +527,7 @@ public Point GetDriverLocationOffset () /// The location offset. public Point GetDriverLocationOffsetFromCurrent () { - var topFrame = DriverFrame; + var topFrame = new Rect (0, 0, Driver.Cols, Driver.Rows); var currentFrame = Application.Current.Frame; return new Point (topFrame.X - currentFrame.X - (topFrame.X != currentFrame.X ? 1 : 0), topFrame.Y - currentFrame.Y - (topFrame.Y != currentFrame.Y ? 1 : 0)); diff --git a/Terminal.Gui/Views/ContextMenu.cs b/Terminal.Gui/Views/ContextMenu.cs index 6ddf55d222..2c94e50b86 100644 --- a/Terminal.Gui/Views/ContextMenu.cs +++ b/Terminal.Gui/Views/ContextMenu.cs @@ -92,7 +92,7 @@ public void Show () } container = Application.Current; container.Closing += Container_Closing; - var frame = View.DriverFrame; + var frame = new Rect (0, 0, View.Driver.Cols, View.Driver.Rows); var position = Position; if (Host != null) { Host.ViewToScreen (frame.X, frame.Y, out int x, out int y); diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 1924b27676..8d8bea6638 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -557,7 +557,7 @@ public override void Redraw (Rect bounds) return; } var savedClip = Driver.Clip; - Driver.Clip = DriverFrame; + Driver.Clip = new Rect (0, 0, Driver.Cols, Driver.Rows); Driver.SetAttribute (GetNormalColor ()); diff --git a/UnitTests/View/NavigationTests.cs b/UnitTests/View/NavigationTests.cs index 3c3edb6c38..cbbb63a92d 100644 --- a/UnitTests/View/NavigationTests.cs +++ b/UnitTests/View/NavigationTests.cs @@ -1090,15 +1090,13 @@ public void ScreenToView_ViewToScreen_FindDeepestView_Full_Top () Application.Begin (top); Assert.Equal (Application.Current, top); - Assert.Equal (new Rect (0, 0, 80, 25), View.DriverFrame); - Assert.Equal (View.DriverFrame, top.Frame); + Assert.Equal (new Rect (0, 0, 80, 25), new Rect (0, 0, View.Driver.Cols, View.Driver.Rows)); + Assert.Equal (new Rect (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); Assert.Equal (new Rect (0, 0, 80, 25), top.Frame); - Assert.Equal ((Point.Empty, Point.Empty), View.DriverFrameOffset); ((FakeDriver)Application.Driver).SetBufferSize (20, 10); - Assert.Equal (View.DriverFrame, top.Frame); + Assert.Equal (new Rect (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); Assert.Equal (new Rect (0, 0, 20, 10), top.Frame); - Assert.Equal ((Point.Empty, Point.Empty), View.DriverFrameOffset); _ = TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────┐ │ │ @@ -1205,16 +1203,14 @@ public void ScreenToView_ViewToScreen_FindDeepestView_Smaller_Top () Application.Begin (top); Assert.Equal (Application.Current, top); - Assert.Equal (new Rect (0, 0, 80, 25), View.DriverFrame); - Assert.NotEqual (View.DriverFrame, top.Frame); + Assert.Equal (new Rect (0, 0, 80, 25), new Rect (0, 0, View.Driver.Cols, View.Driver.Rows)); + Assert.NotEqual (new Rect (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); Assert.Equal (new Rect (3, 2, 20, 10), top.Frame); - Assert.Equal ((new (3, 2), new Point (-57, -13)), View.DriverFrameOffset); ((FakeDriver)Application.Driver).SetBufferSize (30, 20); - Assert.Equal (new Rect (0, 0, 30, 20), View.DriverFrame); - Assert.NotEqual (View.DriverFrame, top.Frame); + Assert.Equal (new Rect (0, 0, 30, 20), new Rect (0, 0, View.Driver.Cols, View.Driver.Rows)); + Assert.NotEqual (new Rect (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); Assert.Equal (new Rect (3, 2, 20, 10), top.Frame); - Assert.Equal ((new (3, 2), new Point (-7, -8)), View.DriverFrameOffset); var frame = TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────┐ │ │ From bc0bf2feca67df51cdea544500714d54fca6fcbc Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 29 Apr 2023 15:01:00 +0100 Subject: [PATCH 08/16] Replace _frame with Frame as requested. --- Terminal.Gui/View/ViewLayout.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Terminal.Gui/View/ViewLayout.cs b/Terminal.Gui/View/ViewLayout.cs index b88690c1fd..0cdcdb9e72 100644 --- a/Terminal.Gui/View/ViewLayout.cs +++ b/Terminal.Gui/View/ViewLayout.cs @@ -495,10 +495,10 @@ protected void ClearLayoutNeeded () public Point ScreenToView (int x, int y) { if (SuperView == null) { - return new Point (x - _frame.X, y - _frame.Y); + return new Point (x - Frame.X, y - Frame.Y); } else { var parent = SuperView.ScreenToView (x, y); - return new Point (parent.X - _frame.X, parent.Y - _frame.Y); + return new Point (parent.X - Frame.X, parent.Y - Frame.Y); } } @@ -512,10 +512,10 @@ public Point ScreenToBounds (int x, int y) { if (SuperView == null) { var boundsOffset = GetBoundsOffset (); - return new Point (x - _frame.X + boundsOffset.X, y - _frame.Y + boundsOffset.Y); + return new Point (x - Frame.X + boundsOffset.X, y - Frame.Y + boundsOffset.Y); } else { var parent = SuperView.ScreenToView (x, y); - return new Point (parent.X - _frame.X, parent.Y - _frame.Y); + return new Point (parent.X - Frame.X, parent.Y - Frame.Y); } } From 2d9b874364ebc0489c647892bee08cfdda510d6c Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 29 Apr 2023 16:17:03 +0100 Subject: [PATCH 09/16] Fix xml document comment. --- Terminal.Gui/View/View.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Terminal.Gui/View/View.cs b/Terminal.Gui/View/View.cs index da121e2628..a1e6538eab 100644 --- a/Terminal.Gui/View/View.cs +++ b/Terminal.Gui/View/View.cs @@ -510,7 +510,8 @@ protected override void Dispose (bool disposing) } /// - /// Gets the superview location offset relative to the . + /// Gets the superview location offset relative to the size + /// which is measured by the and . /// /// The location offset. public Point GetDriverLocationOffset () @@ -522,7 +523,7 @@ public Point GetDriverLocationOffset () } /// - /// Gets the location offset relative to the . + /// Gets the location offset relative to the size. /// /// The location offset. public Point GetDriverLocationOffsetFromCurrent () From 77f0b43245cfb51d3349315eb6bd27b74b15f0b6 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 30 Apr 2023 00:40:24 +0100 Subject: [PATCH 10/16] Compare equality between Dialog and Application.Top. --- UnitTests/Views/ContextMenuTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/UnitTests/Views/ContextMenuTests.cs b/UnitTests/Views/ContextMenuTests.cs index f6a5a522e2..dbcb759538 100644 --- a/UnitTests/Views/ContextMenuTests.cs +++ b/UnitTests/Views/ContextMenuTests.cs @@ -996,6 +996,7 @@ public void Draw_A_ContextMenu_Over_A_Top_Dialog () var rs = Application.Begin (dialog); Assert.Equal (new Rect (2, 2, 15, 4), dialog.Frame); + Assert.Equal (dialog, Application.Top); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌─────────────┐ │ Test │ From 2816f67777220e2a5b13b8b042f0408de96282ac Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 30 Apr 2023 00:41:24 +0100 Subject: [PATCH 11/16] Move GetDriverLocationOffset and GetDriverLocationOffsetFromCurrent to the Menu.cs. --- Terminal.Gui/View/View.cs | 25 ------------------------- Terminal.Gui/Views/Menu.cs | 29 +++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Terminal.Gui/View/View.cs b/Terminal.Gui/View/View.cs index a1e6538eab..c9fea00d5f 100644 --- a/Terminal.Gui/View/View.cs +++ b/Terminal.Gui/View/View.cs @@ -508,30 +508,5 @@ protected override void Dispose (bool disposing) } base.Dispose (disposing); } - - /// - /// Gets the superview location offset relative to the size - /// which is measured by the and . - /// - /// The location offset. - public Point GetDriverLocationOffset () - { - var superViewFrame = SuperView == null ? new Rect (0, 0, Driver.Cols, Driver.Rows) : SuperView.Frame; - var sv = SuperView == null ? Application.Current : SuperView; - return new Point (superViewFrame.X - sv.Frame.X - (superViewFrame.X != sv.Frame.X ? 1 : 0), - superViewFrame.Y - sv.Frame.Y - (superViewFrame.Y != sv.Frame.Y ? 1 : 0)); - } - - /// - /// Gets the location offset relative to the size. - /// - /// The location offset. - public Point GetDriverLocationOffsetFromCurrent () - { - var topFrame = new Rect (0, 0, Driver.Cols, Driver.Rows); - var currentFrame = Application.Current.Frame; - return new Point (topFrame.X - currentFrame.X - (topFrame.X != currentFrame.X ? 1 : 0), - topFrame.Y - currentFrame.Y - (topFrame.Y != currentFrame.Y ? 1 : 0)); - } } } diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 8d8bea6638..a331b61ef4 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -523,7 +523,7 @@ private void Application_RootMouseEvent (MouseEvent me) if (me.View is MenuBar) { return; } - var locationOffset = GetDriverLocationOffsetFromCurrent (); + var locationOffset = host.GetDriverLocationOffsetFromCurrent (); if (SuperView != null && SuperView != Application.Current) { locationOffset.X += SuperView.Border.Thickness.Left; locationOffset.Y += SuperView.Border.Thickness.Top; @@ -881,7 +881,7 @@ public override bool MouseEvent (MouseEvent me) } host.handled = false; bool disabled; - Point locationOffset = GetDriverLocationOffset (); + Point locationOffset = host.GetDriverLocationOffset (); if (SuperView != null && SuperView != Application.Current) { locationOffset.X += SuperView.Border.Thickness.Left; locationOffset.Y += SuperView.Border.Thickness.Top; @@ -2099,5 +2099,30 @@ public override bool OnEnter (View view) return base.OnEnter (view); } + + /// + /// Gets the superview location offset relative to the size + /// which is measured by the and . + /// + /// The location offset. + internal Point GetDriverLocationOffset () + { + var superViewFrame = SuperView == null ? new Rect (0, 0, Driver.Cols, Driver.Rows) : SuperView.Frame; + var sv = SuperView == null ? Application.Current : SuperView; + return new Point (superViewFrame.X - sv.Frame.X - (superViewFrame.X != sv.Frame.X ? 1 : 0), + superViewFrame.Y - sv.Frame.Y - (superViewFrame.Y != sv.Frame.Y ? 1 : 0)); + } + + /// + /// Gets the location offset relative to the size. + /// + /// The location offset. + internal Point GetDriverLocationOffsetFromCurrent () + { + var topFrame = new Rect (0, 0, Driver.Cols, Driver.Rows); + var currentFrame = Application.Current.Frame; + return new Point (topFrame.X - currentFrame.X - (topFrame.X != currentFrame.X ? 1 : 0), + topFrame.Y - currentFrame.Y - (topFrame.Y != currentFrame.Y ? 1 : 0)); + } } } From 14338b7592f4023017e84893e52dedc811cffbd8 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 4 May 2023 13:58:10 +0100 Subject: [PATCH 12/16] Fix merge errors. --- UnitTests/View/NavigationTests.cs | 29 +++++++++++++++++++---------- UnitTests/Views/MenuTests.cs | 18 +++++++++--------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/UnitTests/View/NavigationTests.cs b/UnitTests/View/NavigationTests.cs index cbbb63a92d..d8d420f3b0 100644 --- a/UnitTests/View/NavigationTests.cs +++ b/UnitTests/View/NavigationTests.cs @@ -1133,10 +1133,19 @@ public void ScreenToView_ViewToScreen_FindDeepestView_Full_Top () top.ViewToScreen (3, 2, out col, out row); Assert.Equal (4, col); Assert.Equal (3, row); + Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry)); + Assert.Equal (0, rx); + Assert.Equal (0, ry); Assert.Equal (top, View.FindDeepestView (top, 3, 2, out rx, out ry)); Assert.Equal (3, rx); Assert.Equal (2, ry); Assert.Equal (new Point (13, 2), top.ScreenToView (13, 2)); + top.ViewToScreen (12, 2, out col, out row); + Assert.Equal (13, col); + Assert.Equal (3, row); + Assert.Equal (view, View.FindDeepestView (top, col, row, out rx, out ry)); + Assert.Equal (9, rx); + Assert.Equal (0, ry); top.ViewToScreen (13, 2, out col, out row); Assert.Equal (14, col); Assert.Equal (3, row); @@ -1151,7 +1160,7 @@ public void ScreenToView_ViewToScreen_FindDeepestView_Full_Top () Assert.Equal (14, rx); Assert.Equal (3, ry); // view - Assert.Equal (new Point (-3, -2), view.ScreenToView (0, 0)); + Assert.Equal (new Point (-4, -3), view.ScreenToView (0, 0)); view.Margin.ViewToScreen (-3, -2, out col, out row); Assert.Equal (1, col); Assert.Equal (1, row); @@ -1170,21 +1179,21 @@ public void ScreenToView_ViewToScreen_FindDeepestView_Full_Top () Assert.Equal (top, View.FindDeepestView (top, 0, 0, out rx, out ry)); Assert.Equal (0, rx); Assert.Equal (0, ry); - Assert.Equal (Point.Empty, view.ScreenToView (3, 2)); + Assert.Equal (new Point (-1, -1), view.ScreenToView (3, 2)); view.ViewToScreen (0, 0, out col, out row); Assert.Equal (4, col); Assert.Equal (3, row); Assert.Equal (view, View.FindDeepestView (top, 4, 3, out rx, out ry)); Assert.Equal (0, rx); Assert.Equal (0, ry); - Assert.Equal (new Point (10, 0), view.ScreenToView (13, 2)); + Assert.Equal (new Point (9, -1), view.ScreenToView (13, 2)); view.ViewToScreen (10, 0, out col, out row); Assert.Equal (14, col); Assert.Equal (3, row); Assert.Equal (top, View.FindDeepestView (top, 14, 3, out rx, out ry)); Assert.Equal (14, rx); Assert.Equal (3, ry); - Assert.Equal (new Point (11, 1), view.ScreenToView (14, 3)); + Assert.Equal (new Point (10, 0), view.ScreenToView (14, 3)); view.ViewToScreen (11, 1, out col, out row); Assert.Equal (15, col); Assert.Equal (4, row); @@ -1268,7 +1277,7 @@ public void ScreenToView_ViewToScreen_FindDeepestView_Smaller_Top () Assert.Equal (11, rx); Assert.Equal (1, ry); // view - Assert.Equal (new Point (-6, -4), view.ScreenToView (0, 0)); + Assert.Equal (new Point (-7, -5), view.ScreenToView (0, 0)); view.Margin.ViewToScreen (-6, -4, out col, out row); Assert.Equal (1, col); Assert.Equal (1, row); @@ -1284,35 +1293,35 @@ public void ScreenToView_ViewToScreen_FindDeepestView_Smaller_Top () Assert.Null (View.FindDeepestView (top, 1, 1, out rx, out ry)); Assert.Equal (0, rx); Assert.Equal (0, ry); - Assert.Equal (new Point (-3, -2), view.ScreenToView (3, 2)); + Assert.Equal (new Point (-4, -3), view.ScreenToView (3, 2)); view.ViewToScreen (-3, -2, out col, out row); Assert.Equal (4, col); Assert.Equal (3, row); Assert.Equal (top, View.FindDeepestView (top, 4, 3, out rx, out ry)); Assert.Equal (1, rx); Assert.Equal (1, ry); - Assert.Equal (Point.Empty, view.ScreenToView (6, 4)); + Assert.Equal (new Point (-1, -1), view.ScreenToView (6, 4)); view.ViewToScreen (0, 0, out col, out row); Assert.Equal (7, col); Assert.Equal (5, row); Assert.Equal (view, View.FindDeepestView (top, 7, 5, out rx, out ry)); Assert.Equal (0, rx); Assert.Equal (0, ry); - Assert.Equal (new Point (7, 0), view.ScreenToView (13, 4)); + Assert.Equal (new Point (6, -1), view.ScreenToView (13, 4)); view.ViewToScreen (7, 0, out col, out row); Assert.Equal (14, col); Assert.Equal (5, row); Assert.Equal (view, View.FindDeepestView (top, 14, 5, out rx, out ry)); Assert.Equal (7, rx); Assert.Equal (0, ry); - Assert.Equal (new Point (8, -1), view.ScreenToView (14, 3)); + Assert.Equal (new Point (7, -2), view.ScreenToView (14, 3)); view.ViewToScreen (8, -1, out col, out row); Assert.Equal (15, col); Assert.Equal (4, row); Assert.Equal (top, View.FindDeepestView (top, 15, 4, out rx, out ry)); Assert.Equal (12, rx); Assert.Equal (2, ry); - Assert.Equal (new Point (17, -1), view.ScreenToView (23, 3)); + Assert.Equal (new Point (16, -2), view.ScreenToView (23, 3)); view.ViewToScreen (17, -1, out col, out row); Assert.Equal (24, col); Assert.Equal (4, row); diff --git a/UnitTests/Views/MenuTests.cs b/UnitTests/Views/MenuTests.cs index 25f81a2674..b8db4bc835 100644 --- a/UnitTests/Views/MenuTests.cs +++ b/UnitTests/Views/MenuTests.cs @@ -1690,7 +1690,7 @@ public void MenuBar_In_Window_Without_Other_Views_With_Top_Init_With_Parameterle └──────────────────────────────────────┘", output); Assert.True (win.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); - top.Redraw (top.Bounds); + top.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1714,7 +1714,7 @@ public void MenuBar_In_Window_Without_Other_Views_With_Top_Init_With_Parameterle └──────────────────────────────────────┘", output); Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - top.Redraw (top.Bounds); + top.Draw(); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1726,7 +1726,7 @@ public void MenuBar_In_Window_Without_Other_Views_With_Top_Init_With_Parameterle └──────────────────────────────────────┘", output); Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - top.Redraw (top.Bounds); + top.Draw(); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1853,7 +1853,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init () └──────────────────────────────────────┘", output); Assert.True (win.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); - win.Redraw (win.Bounds); + win.Draw(); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1877,7 +1877,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init () └──────────────────────────────────────┘", output); Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - win.Redraw (win.Bounds); + win.Draw(); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1889,7 +1889,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init () └──────────────────────────────────────┘", output); Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - win.Redraw (win.Bounds); + win.Draw(); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1920,7 +1920,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () └──────────────────────────────────────┘", output); Assert.True (top.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); - top.Redraw (top.Bounds); + top.Draw(); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1944,7 +1944,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () └──────────────────────────────────────┘", output); Assert.True (((MenuBar)top.Subviews [0]).openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - top.Redraw (top.Bounds); + top.Draw(); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1956,7 +1956,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () └──────────────────────────────────────┘", output); Assert.True (((MenuBar)top.Subviews [0]).openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - top.Redraw (top.Bounds); + top.Draw(); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ From dd3a763fa531eb8f3c46d199730fa3dcaf08ac91 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 4 May 2023 14:44:17 +0100 Subject: [PATCH 13/16] Ensure menu is closed on click. --- Terminal.Gui/Views/Menu.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 0c5d7665cd..6a4dea7aa4 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -1988,6 +1988,11 @@ public override bool MouseEvent (MouseEvent me) Activate (i); } return true; + } else if (i == Menus.Length - 1 && me.Flags == MouseFlags.Button1Clicked) { + if (IsMenuOpen && !Menus [i].IsTopLevel) { + CloseAllMenus (); + return true; + } } pos += leftPadding + Menus [i].TitleLength + rightPadding; } From 3c267c390cdc120b0f075336f7ee041f9be547cd Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 5 May 2023 20:36:01 +0100 Subject: [PATCH 14/16] Force Height always be 1 to avoid mouse events respond even outside bounds. --- Terminal.Gui/Views/TextField.cs | 7 ++++++- UICatalog/Scenarios/Text.cs | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Terminal.Gui/Views/TextField.cs b/Terminal.Gui/Views/TextField.cs index a689bf192d..f4c8e3b6aa 100644 --- a/Terminal.Gui/Views/TextField.cs +++ b/Terminal.Gui/Views/TextField.cs @@ -293,7 +293,12 @@ public override bool OnLeave (View view) public override Rect Frame { get => base.Frame; set { - base.Frame = value; + if (value.Height > 1) { + base.Frame = new Rect(value.X, value.Y, value.Width, 1); + Height = 1; + } else { + base.Frame = value; + } Adjust (); } } diff --git a/UICatalog/Scenarios/Text.cs b/UICatalog/Scenarios/Text.cs index ae357912c8..9e905b55a4 100644 --- a/UICatalog/Scenarios/Text.cs +++ b/UICatalog/Scenarios/Text.cs @@ -21,6 +21,7 @@ public override void Setup () X = 1, Y = 0, Width = Dim.Percent (50) - 1, + // Height will be replaced with 1 Height = 2 }; @@ -51,7 +52,7 @@ void TextField_TextChanging (object sender, TextChangingEventArgs e) // TextView is a rich (as in functionality, not formatting) text editing control var textView = new TextView () { X = 1, - Y = Pos.Bottom (textField), + Y = Pos.Bottom (textField) + 1, Width = Dim.Percent (50) - 1, Height = Dim.Percent (30), }; From 0f54fdd03a681a91001e2b5018de7b4770e0fbc6 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 5 May 2023 20:37:43 +0100 Subject: [PATCH 15/16] Recovering UseSubMenusSingleFrame hope doesn't break again. --- UICatalog/UICatalog.cs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs index f3ca107bb8..9ef655d5ee 100644 --- a/UICatalog/UICatalog.cs +++ b/UICatalog/UICatalog.cs @@ -250,6 +250,7 @@ static Scenario RunUICatalogTopLevel () /// the command line) and each time a Scenario ends. /// public class UICatalogTopLevel : Toplevel { + public MenuItem? miUseSubMenusSingleFrame; public MenuItem? miIsMenuBorderDisabled; public MenuItem? miIsMouseDisabled; public MenuItem? miEnableConsoleScrolling; @@ -491,18 +492,36 @@ List CreateDiagnosticMenuItems () CreateEnableConsoleScrollingMenuItems (), CreateDisabledEnabledMouseItems (), CreateDisabledEnabledMenuBorder (), + CreateDisabledEnableUseSubMenusSingleFrame (), CreateKeybindingsMenuItems () }; return menuItems; } + MenuItem [] CreateDisabledEnableUseSubMenusSingleFrame () + { + List menuItems = new List (); + miUseSubMenusSingleFrame = new MenuItem { + Title = "Enable _Sub-Menus Single Frame" + }; + miUseSubMenusSingleFrame.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miUseSubMenusSingleFrame!.Title!.ToString ()!.Substring (8, 1) [0]; + miUseSubMenusSingleFrame.CheckType |= MenuItemCheckStyle.Checked; + miUseSubMenusSingleFrame.Action += () => { + miUseSubMenusSingleFrame.Checked = (bool)!miUseSubMenusSingleFrame.Checked!; + MenuBar.UseSubMenusSingleFrame = (bool)miUseSubMenusSingleFrame.Checked; + }; + menuItems.Add (miUseSubMenusSingleFrame); + + return menuItems.ToArray (); + } + MenuItem [] CreateDisabledEnabledMenuBorder () { List menuItems = new List (); miIsMenuBorderDisabled = new MenuItem { - Title = "Disable _Menu Border" + Title = "Disable Menu _Border" }; - miIsMenuBorderDisabled.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miIsMenuBorderDisabled!.Title!.ToString ()!.Substring (1, 1) [0]; + miIsMenuBorderDisabled.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miIsMenuBorderDisabled!.Title!.ToString ()!.Substring (14, 1) [0]; miIsMenuBorderDisabled.CheckType |= MenuItemCheckStyle.Checked; miIsMenuBorderDisabled.Action += () => { miIsMenuBorderDisabled.Checked = (bool)!miIsMenuBorderDisabled.Checked!; @@ -709,6 +728,11 @@ public void ConfigChanged () _themeMenuItems = ((UICatalogTopLevel)Application.Top).CreateThemeMenuItems (); _themeMenuBarItem!.Children = _themeMenuItems; + foreach (var mi in _themeMenuItems!) { + if (mi != null && mi.Parent == null) { + mi.Parent = _themeMenuBarItem; + } + } var checkedThemeMenu = _themeMenuItems?.Where (m => m?.Checked ?? false).FirstOrDefault (); if (checkedThemeMenu != null) { From b97f3181fd6319e0bc306bd81db2a60ad4e3a302 Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 5 May 2023 20:39:01 +0100 Subject: [PATCH 16/16] Fix bugs and made requested changes. --- Terminal.Gui/Views/Menu.cs | 86 ++++++---- UnitTests/Views/ContextMenuTests.cs | 113 ++++++++++++- UnitTests/Views/MenuTests.cs | 237 +++++++++++++++++++--------- 3 files changed, 333 insertions(+), 103 deletions(-) diff --git a/Terminal.Gui/Views/Menu.cs b/Terminal.Gui/Views/Menu.cs index 6a4dea7aa4..b0cc4101d4 100644 --- a/Terminal.Gui/Views/Menu.cs +++ b/Terminal.Gui/Views/Menu.cs @@ -202,7 +202,7 @@ public MenuItemCheckStyle CheckType { /// Gets the parent for this . /// /// The parent. - public MenuItem Parent { get; internal set; } + public MenuItem Parent { get; set; } /// /// Gets if this is from a sub-menu. @@ -443,7 +443,7 @@ internal static Rect MakeFrame (int x, int y, MenuItem [] items, Menu parent = n } int minX = x; int minY = y; - var borderOffset = border != LineStyle.None ? 2 : 0; // This 2 is frame border? + var borderOffset = 2; // This 2 is for the space around int maxW = (items.Max (z => z?.Width) ?? 0) + borderOffset; int maxH = items.Length + borderOffset; if (parent != null && x + maxW > Driver.Cols) { @@ -518,18 +518,33 @@ private void Current_TerminalResized (object sender, SizeChangedEventArgs e) } } + /// + public override void OnVisibleChanged () + { + base.OnVisibleChanged (); + if (Visible) { + Application.RootMouseEvent += Application_RootMouseEvent; + } else { + Application.RootMouseEvent -= Application_RootMouseEvent; + } + } + private void Application_RootMouseEvent (MouseEvent me) { if (me.View is MenuBar) { return; } - var locationOffset = host.GetDriverLocationOffsetFromCurrent (); + var locationOffset = host.GetScreenOffsetFromCurrent (); if (SuperView != null && SuperView != Application.Current) { locationOffset.X += SuperView.Border.Thickness.Left; locationOffset.Y += SuperView.Border.Thickness.Top; } var view = View.FindDeepestView (this, me.X + locationOffset.X, me.Y + locationOffset.Y, out int rx, out int ry); if (view == this) { + if (!Visible) { + throw new InvalidOperationException ("This shouldn't running on a invisible menu!"); + } + var nme = new MouseEvent () { X = rx, Y = ry, @@ -674,7 +689,9 @@ public override void OnDrawContent (Rect contentArea) private void Current_DrawContentComplete (object sender, DrawEventArgs e) { - OnDrawContent (Bounds); + if (Visible) { + OnDrawContent (Bounds); + } } public override void PositionCursor () @@ -881,13 +898,7 @@ public override bool MouseEvent (MouseEvent me) } host.handled = false; bool disabled; - Point locationOffset = host.GetDriverLocationOffset (); - if (SuperView != null && SuperView != Application.Current) { - locationOffset.X += SuperView.Border.Thickness.Left; - locationOffset.Y += SuperView.Border.Thickness.Top; - } - var meYOffset = Border.Thickness.Top + locationOffset.Y; - var meY = me.Y - meYOffset; + var meY = me.Y - (Border == null ? 0 : Border.Thickness.Top); if (me.Flags == MouseFlags.Button1Clicked) { disabled = false; if (meY < 0) @@ -1313,7 +1324,7 @@ internal Menu openCurrentMenu { set { if (ocm != value) { ocm = value; - if (ocm.current > -1) { + if (ocm != null && ocm.current > -1) { OnMenuOpened (); } } @@ -1420,8 +1431,11 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem subMenu = null) for (int i = 0; i < index; i++) pos += Menus [i].TitleLength + (Menus [i].Help.ConsoleWidth > 0 ? Menus [i].Help.ConsoleWidth + 2 : 0) + leftPadding + rightPadding; - var locationOffset = GetDriverLocationOffset (); + var locationOffset = Point.Empty; // if SuperView is null then it's from a ContextMenu + if (SuperView == null) { + locationOffset = GetScreenOffset (); + } if (SuperView != null && SuperView != Application.Current) { locationOffset.X += SuperView.Border.Thickness.Left; locationOffset.Y += SuperView.Border.Thickness.Top; @@ -1446,15 +1460,15 @@ internal void OpenMenu (int index, int sIndex = -1, MenuBarItem subMenu = null) openCurrentMenu = new Menu (this, last.Frame.Left + last.Frame.Width + locationOffset.X, last.Frame.Top + locationOffset.Y + last.current, subMenu, last, MenusBorderStyle); } else { var first = openSubMenu.Count > 0 ? openSubMenu.First () : openMenu; + // 2 is for the parent and the separator var mbi = new MenuItem [2 + subMenu.Children.Length]; mbi [0] = new MenuItem () { Title = subMenu.Title, Parent = subMenu }; mbi [1] = null; for (int j = 0; j < subMenu.Children.Length; j++) { mbi [j + 2] = subMenu.Children [j]; } - var newSubMenu = new MenuBarItem (mbi); - ViewToScreen (first.Frame.Left, first.Frame.Top, out int rx, out int ry); - openCurrentMenu = new Menu (this, rx, ry, newSubMenu, null, MenusBorderStyle); + var newSubMenu = new MenuBarItem (mbi) { Parent = subMenu }; + openCurrentMenu = new Menu (this, first.Frame.Left, first.Frame.Top, newSubMenu, null, MenusBorderStyle); last.Visible = false; Application.GrabMouse (openCurrentMenu); } @@ -1607,6 +1621,14 @@ internal bool CloseMenu (bool reopen = false, bool isSubMenu = false, bool ignor if (!reopen) { selected = -1; } + if (openSubMenu != null) { + openSubMenu = null; + } + if (openCurrentMenu != null) { + Application.Current.Remove (openCurrentMenu); + openCurrentMenu.Dispose (); + openCurrentMenu = null; + } LastFocused.SetFocus (); } else if (openSubMenu == null || openSubMenu.Count == 0) { CloseAllMenus (); @@ -1675,7 +1697,7 @@ internal void RemoveAllOpensSubMenus () internal void CloseAllMenus () { if (!isMenuOpening && !isMenuClosing) { - if (openSubMenu != null && !CloseMenu (false, true)) + if (openSubMenu != null && !CloseMenu (false, true, true)) return; if (!CloseMenu (false)) return; @@ -1983,16 +2005,19 @@ public override bool MouseEvent (MouseEvent me) } Activate (i); } - } else { - if (IsMenuOpen) + } else if (IsMenuOpen) { + if (!UseSubMenusSingleFrame || (UseSubMenusSingleFrame && openCurrentMenu != null + && openCurrentMenu.barItems.Parent != null && openCurrentMenu.barItems.Parent.Parent != Menus [i])) { + Activate (i); + } } return true; } else if (i == Menus.Length - 1 && me.Flags == MouseFlags.Button1Clicked) { if (IsMenuOpen && !Menus [i].IsTopLevel) { CloseAllMenus (); return true; - } + } } pos += leftPadding + Menus [i].TitleLength + rightPadding; } @@ -2106,28 +2131,29 @@ public override bool OnEnter (View view) } /// - /// Gets the superview location offset relative to the size - /// which is measured by the and . + /// Gets the superview location offset relative to the location. /// /// The location offset. - internal Point GetDriverLocationOffset () + internal Point GetScreenOffset () { var superViewFrame = SuperView == null ? new Rect (0, 0, Driver.Cols, Driver.Rows) : SuperView.Frame; var sv = SuperView == null ? Application.Current : SuperView; - return new Point (superViewFrame.X - sv.Frame.X - (superViewFrame.X != sv.Frame.X ? 1 : 0), - superViewFrame.Y - sv.Frame.Y - (superViewFrame.Y != sv.Frame.Y ? 1 : 0)); + var boundsOffset = sv.GetBoundsOffset (); + return new Point (superViewFrame.X - sv.Frame.X - boundsOffset.X, + superViewFrame.Y - sv.Frame.Y - boundsOffset.Y); } /// - /// Gets the location offset relative to the size. + /// Gets the location offset relative to the location. /// /// The location offset. - internal Point GetDriverLocationOffsetFromCurrent () + internal Point GetScreenOffsetFromCurrent () { - var topFrame = new Rect (0, 0, Driver.Cols, Driver.Rows); + var screen = new Rect (0, 0, Driver.Cols, Driver.Rows); var currentFrame = Application.Current.Frame; - return new Point (topFrame.X - currentFrame.X - (topFrame.X != currentFrame.X ? 1 : 0), - topFrame.Y - currentFrame.Y - (topFrame.Y != currentFrame.Y ? 1 : 0)); + var boundsOffset = Application.Top.GetBoundsOffset (); + return new Point (screen.X - currentFrame.X - boundsOffset.X + , screen.Y - currentFrame.Y - boundsOffset.Y); } } } diff --git a/UnitTests/Views/ContextMenuTests.cs b/UnitTests/Views/ContextMenuTests.cs index 30e7e04b57..7d5d044081 100644 --- a/UnitTests/Views/ContextMenuTests.cs +++ b/UnitTests/Views/ContextMenuTests.cs @@ -989,7 +989,7 @@ public void Draw_A_ContextMenu_Over_A_Top_Dialog () ((FakeDriver)Application.Driver).SetBufferSize (20, 15); Assert.Equal (new Rect (0, 0, 20, 15), Application.Driver.Clip); - TestHelpers.AssertDriverContentsWithFrameAre (@"", output); + TestHelpers.AssertDriverContentsWithFrameAre ("", output); var dialog = new Dialog () { X = 2, Y = 2, Width = 15, Height = 4 }; dialog.Add (new TextField ("Test") { X = Pos.Center (), Width = 10 }); @@ -1029,5 +1029,116 @@ public void Draw_A_ContextMenu_Over_A_Top_Dialog () Application.End (rs); } + + [Fact, AutoInitShutdown] + public void Draw_A_ContextMenu_Over_A_Borderless_Top () + { + ((FakeDriver)Application.Driver).SetBufferSize (20, 15); + + Assert.Equal (new Rect (0, 0, 20, 15), Application.Driver.Clip); + TestHelpers.AssertDriverContentsWithFrameAre ("", output); + + var top = new Toplevel () { X = 2, Y = 2, Width = 15, Height = 4 }; + top.Add (new TextField ("Test") { X = Pos.Center (), Width = 10 }); + var rs = Application.Begin (top); + + Assert.Equal (new Rect (2, 2, 15, 4), top.Frame); + Assert.Equal (top, Application.Top); + TestHelpers.AssertDriverContentsWithFrameAre (@" + Test", output); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 8, + Y = 2, + Flags = MouseFlags.Button3Clicked + }); + + var firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + TestHelpers.AssertDriverContentsWithFrameAre (@" + Test +┌─────────────────── +│ Select All Ctrl+ +│ Delete All Ctrl+ +│ Copy Ctrl+ +│ Cut Ctrl+ +│ Paste Ctrl+ +│ Undo Ctrl+ +│ Redo Ctrl+ +└───────────────────", output); + + Application.End (rs); + } + + [Fact, AutoInitShutdown] + public void UseSubMenusSingleFrame_True_By_Mouse () + { + var cm = new ContextMenu (5, 10, + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + ) { UseSubMenusSingleFrame = true }; + + cm.Show (); + var rs = Application.Begin (Application.Top); + + Assert.Equal (new Rect (5, 11, 10, 5), Application.Top.Subviews [0].Frame); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌────────┐ + │ One │ + │ Two ►│ + │ Three │ + └────────┘", output); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 5, + Y = 13, + Flags = MouseFlags.Button1Clicked + }); + + var firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + Assert.Equal (new Rect (5, 11, 10, 5), Application.Top.Subviews [0].Frame); + Assert.Equal (new Rect (5, 11, 15, 6), Application.Top.Subviews [1].Frame); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌─────────────┐ + │◄ Two │ + ├─────────────┤ + │ Sub-Menu 1 │ + │ Sub-Menu 2 │ + └─────────────┘", output); + + ReflectionTools.InvokePrivate ( + typeof (Application), + "ProcessMouseEvent", + new MouseEvent () { + X = 5, + Y = 12, + Flags = MouseFlags.Button1Clicked + }); + + firstIteration = false; + Application.RunMainLoopIteration (ref rs, true, ref firstIteration); + Assert.Equal (new Rect (5, 11, 10, 5), Application.Top.Subviews [0].Frame); + TestHelpers.AssertDriverContentsWithFrameAre (@" + ┌────────┐ + │ One │ + │ Two ►│ + │ Three │ + └────────┘", output); + + Application.End (rs); + } } } diff --git a/UnitTests/Views/MenuTests.cs b/UnitTests/Views/MenuTests.cs index b8db4bc835..fed55bf986 100644 --- a/UnitTests/Views/MenuTests.cs +++ b/UnitTests/Views/MenuTests.cs @@ -867,15 +867,15 @@ public void UseSubMenusSingleFrame_False_By_Mouse () public void UseSubMenusSingleFrame_True_By_Keyboard () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }); + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -951,15 +951,15 @@ public void UseSubMenusSingleFrame_True_By_Keyboard () public void UseSubMenusSingleFrame_True_By_Mouse () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }); + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }); Application.Top.Add (menu); Application.Begin (Application.Top); @@ -1714,7 +1714,7 @@ public void MenuBar_In_Window_Without_Other_Views_With_Top_Init_With_Parameterle └──────────────────────────────────────┘", output); Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - top.Draw(); + top.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1726,7 +1726,7 @@ public void MenuBar_In_Window_Without_Other_Views_With_Top_Init_With_Parameterle └──────────────────────────────────────┘", output); Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - top.Draw(); + top.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1853,7 +1853,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init () └──────────────────────────────────────┘", output); Assert.True (win.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); - win.Draw(); + win.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1877,7 +1877,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init () └──────────────────────────────────────┘", output); Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - win.Draw(); + win.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1889,7 +1889,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init () └──────────────────────────────────────┘", output); Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - win.Draw(); + win.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1920,7 +1920,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () └──────────────────────────────────────┘", output); Assert.True (top.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); - top.Draw(); + top.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1944,7 +1944,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () └──────────────────────────────────────┘", output); Assert.True (((MenuBar)top.Subviews [0]).openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - top.Draw(); + top.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -1956,7 +1956,7 @@ public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init_With_Run_T () └──────────────────────────────────────┘", output); Assert.True (((MenuBar)top.Subviews [0]).openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); - top.Draw(); + top.Draw (); TestHelpers.AssertDriverContentsWithFrameAre (@" ┌──────────────────────────────────────┐ │ File Edit │ @@ -2124,21 +2124,21 @@ public void Menu_With_Separator_Disabled_Border () menu.OpenMenu (); Application.Refresh (); TestHelpers.AssertDriverContentsWithFrameAre (@" - File - Open Open a file Ctrl+O -────────────────────────── - Quit ", output); + File + Open Open a file Ctrl+O +──────────────────────────── + Quit ", output); } [Fact, AutoInitShutdown] public void DrawFrame_With_Positive_Positions_Disabled_Border () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem (new MenuItem [] { - new MenuItem ("One", "", null), - new MenuItem ("Two", "", null) - }) - }) { MenusBorderStyle = LineStyle.None }; + new MenuBarItem (new MenuItem [] { + new MenuItem ("One", "", null), + new MenuItem ("Two", "", null) + }) + }) { MenusBorderStyle = LineStyle.None }; Assert.Equal (Point.Empty, new Point (menu.Frame.X, menu.Frame.Y)); @@ -2220,15 +2220,16 @@ public void DrawFrame_With_Negative_Positions_Disabled_Border () public void UseSubMenusSingleFrame_False_Disabled_Border () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }) { MenusBorderStyle = LineStyle.None }; + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }) { MenusBorderStyle = LineStyle.None }; + menu.UseKeysUpDownAsKeysLeftRight = true; Application.Top.Add (menu); Application.Begin (Application.Top); @@ -2241,20 +2242,18 @@ public void UseSubMenusSingleFrame_False_Disabled_Border () var expected = @" Numbers One - Two ► - Three -"; + Two ► + Three "; _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); Assert.True (Application.Top.Subviews [1].ProcessKey (new KeyEvent (Key.CursorDown, null))); Application.Top.Draw (); expected = @" - Numbers - One - Two ► Sub-Menu 1 - Three Sub-Menu 2 -"; + Numbers + One + Two ► Sub-Menu 1 + Three Sub-Menu 2"; _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); } @@ -2263,15 +2262,15 @@ Three Sub-Menu 2 public void UseSubMenusSingleFrame_True_Disabled_Border () { var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem ("Numbers", new MenuItem [] { - new MenuItem ("One", "", null), - new MenuBarItem ("Two", new MenuItem [] { - new MenuItem ("Sub-Menu 1", "", null), - new MenuItem ("Sub-Menu 2", "", null) - }), - new MenuItem ("Three", "", null), - }) - }) { MenusBorderStyle = LineStyle.None }; + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }) { MenusBorderStyle = LineStyle.None }; Application.Top.Add (menu); Application.Begin (Application.Top); @@ -2287,9 +2286,8 @@ public void UseSubMenusSingleFrame_True_Disabled_Border () var expected = @" Numbers One - Two ► - Three -"; + Two ► + Three "; _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); @@ -2297,12 +2295,11 @@ public void UseSubMenusSingleFrame_True_Disabled_Border () Assert.True (Application.Top.Subviews [1].ProcessKey (new KeyEvent (Key.Enter, null))); Application.Top.Draw (); expected = @" - Numbers -◄ Two -─────────── - Sub-Menu 1 - Sub-Menu 2 -"; + Numbers +◄ Two +───────────── + Sub-Menu 1 + Sub-Menu 2 "; _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); } @@ -2401,7 +2398,7 @@ void ChangeMenuTitle (string title) "ProcessMouseEvent", new MouseEvent () { X = 20, - Y = 5, + Y = 4, Flags = MouseFlags.Button1Clicked }); @@ -2433,7 +2430,7 @@ void ChangeMenuTitle (string title) "ProcessMouseEvent", new MouseEvent () { X = 20, - Y = 5 + i, + Y = 4 + i, Flags = MouseFlags.Button1Clicked }); @@ -2602,5 +2599,101 @@ public void Resizing_Close_Menus () Application.End (rs); } + + [Fact, AutoInitShutdown] + public void UseSubMenusSingleFrame_True_Without_Border () + { + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem ("Numbers", new MenuItem [] { + new MenuItem ("One", "", null), + new MenuBarItem ("Two", new MenuItem [] { + new MenuItem ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) + }), + new MenuItem ("Three", "", null), + }) + }) { UseSubMenusSingleFrame = true, MenusBorderStyle = LineStyle.None }; + + Application.Top.Add (menu); + Application.Begin (Application.Top); + + Assert.Equal (Point.Empty, new Point (menu.Frame.X, menu.Frame.Y)); + Assert.True (menu.UseSubMenusSingleFrame); + Assert.Equal (LineStyle.None, menu.MenusBorderStyle); + + Application.Top.Draw (); + var expected = @" + Numbers +"; + + var pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (1, 0, 8, 1), pos); + + Assert.True (menu.MouseEvent (new MouseEvent () { + X = 1, + Y = 0, + Flags = MouseFlags.Button1Pressed, + View = menu + })); + Application.Top.Draw (); + expected = @" + Numbers + One + Two ► + Three +"; + + pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (1, 0, 8, 4), pos); + + Assert.False (menu.MouseEvent (new MouseEvent () { + X = 1, + Y = 2, + Flags = MouseFlags.Button1Clicked, + View = Application.Top.Subviews [1] + })); + Application.Top.Draw (); + expected = @" + Numbers +◄ Two +───────────── + Sub-Menu 1 + Sub-Menu 2 +"; + + pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (1, 0, 13, 5), pos); + + Assert.False (menu.MouseEvent (new MouseEvent () { + X = 1, + Y = 1, + Flags = MouseFlags.Button1Clicked, + View = Application.Top.Subviews [2] + })); + Application.Top.Draw (); + expected = @" + Numbers + One + Two ► + Three +"; + + pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (1, 0, 8, 4), pos); + + Assert.False (menu.MouseEvent (new MouseEvent () { + X = 70, + Y = 2, + Flags = MouseFlags.Button1Clicked, + View = Application.Top + })); + Application.Top.Draw (); + expected = @" + Numbers +"; + + pos = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); + Assert.Equal (new Rect (1, 0, 8, 1), pos); + } } }