diff --git a/Terminal.Gui/Application.cs b/Terminal.Gui/Application.cs index 4dd46e8332..bc42520541 100644 --- a/Terminal.Gui/Application.cs +++ b/Terminal.Gui/Application.cs @@ -1208,9 +1208,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) { @@ -1243,7 +1243,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..c9fea00d5f 100644 --- a/Terminal.Gui/View/View.cs +++ b/Terminal.Gui/View/View.cs @@ -434,7 +434,7 @@ public override bool Enabled { } } } - + /// /// Event fired when the value is being changed. /// @@ -481,7 +481,7 @@ bool CanBeVisible (View view) return true; } - + /// /// Pretty prints the View /// diff --git a/Terminal.Gui/Views/ContextMenu.cs b/Terminal.Gui/Views/ContextMenu.cs index 13f0b66f2b..2c94e50b86 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. @@ -79,7 +79,6 @@ public void Dispose () } if (container != null) { container.Closing -= Container_Closing; - container.TerminalResized -= Container_Resized; } } @@ -91,13 +90,12 @@ public void Show () if (menuBar != null) { Hide (); } - container = Application.Top; + container = Application.Current; container.Closing += Container_Closing; - container.TerminalResized += Container_Resized; - var frame = container.Frame; + var frame = new Rect (0, 0, View.Driver.Cols, View.Driver.Rows); 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 +117,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; } @@ -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 0014235254..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) { @@ -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,10 +511,40 @@ 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.CloseAllMenus (); + } + } + + /// + public override void OnVisibleChanged () + { + base.OnVisibleChanged (); + if (Visible) { + Application.RootMouseEvent += Application_RootMouseEvent; + } else { + Application.RootMouseEvent -= Application_RootMouseEvent; + } + } + 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 = 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, @@ -540,8 +571,8 @@ public override void OnDrawContent (Rect contentArea) if (barItems.Children == null) { return; } - var savedClip = Application.Driver.Clip; - Application.Driver.Clip = Application.Top.Frame; + var savedClip = Driver.Clip; + Driver.Clip = new Rect (0, 0, Driver.Cols, Driver.Rows); Driver.SetAttribute (GetNormalColor ()); @@ -549,8 +580,12 @@ public override void OnDrawContent (Rect contentArea) 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 ()); @@ -563,8 +598,12 @@ public override void OnDrawContent (Rect contentArea) 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) @@ -605,9 +644,9 @@ public override void OnDrawContent (Rect contentArea) 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) { @@ -630,15 +669,14 @@ public override void OnDrawContent (Rect contentArea) // 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); } } @@ -651,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 () @@ -858,12 +898,11 @@ public override bool MouseEvent (MouseEvent me) } host.handled = false; bool disabled; - var meYOffset = BorderStyle != LineStyle.None ? 1 : 0; + var meY = me.Y - (Border == null ? 0 : Border.Thickness.Top); 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 +917,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 (); @@ -950,6 +989,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); @@ -1284,7 +1324,7 @@ internal Menu openCurrentMenu { set { if (ocm != value) { ocm = value; - if (ocm.current > -1) { + if (ocm != null && ocm.current > -1) { OnMenuOpened (); } } @@ -1381,7 +1421,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; } @@ -1390,18 +1430,21 @@ 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 = 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; } 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: @@ -1417,21 +1460,21 @@ 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); } 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)) { @@ -1562,7 +1605,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 ()) @@ -1578,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 (); @@ -1621,7 +1672,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 (); } @@ -1637,7 +1688,7 @@ internal void RemoveAllOpensSubMenus () { if (openSubMenu != null) { foreach (var item in openSubMenu) { - Application.Top.Remove (item); + Application.Current.Remove (item); item.Dispose (); } } @@ -1646,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; @@ -1923,7 +1974,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) { @@ -1949,11 +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; } @@ -2065,5 +2129,31 @@ public override bool OnEnter (View view) return base.OnEnter (view); } + + /// + /// Gets the superview location offset relative to the location. + /// + /// The location offset. + internal Point GetScreenOffset () + { + var superViewFrame = SuperView == null ? new Rect (0, 0, Driver.Cols, Driver.Rows) : SuperView.Frame; + var sv = SuperView == null ? Application.Current : SuperView; + 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 location. + /// + /// The location offset. + internal Point GetScreenOffsetFromCurrent () + { + var screen = new Rect (0, 0, Driver.Cols, Driver.Rows); + var currentFrame = Application.Current.Frame; + var boundsOffset = Application.Top.GetBoundsOffset (); + return new Point (screen.X - currentFrame.X - boundsOffset.X + , screen.Y - currentFrame.Y - boundsOffset.Y); + } } } 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/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/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), }; 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) { diff --git a/UnitTests/View/NavigationTests.cs b/UnitTests/View/NavigationTests.cs index 61c5bb54c9..d8d420f3b0 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,256 @@ 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.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.Current, top); + 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); + + ((FakeDriver)Application.Driver).SetBufferSize (20, 10); + Assert.Equal (new Rect (0, 0, View.Driver.Cols, View.Driver.Rows), top.Frame); + Assert.Equal (new Rect (0, 0, 20, 10), top.Frame); + _ = 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 (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); + 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 (-4, -3), 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 (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 (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 (10, 0), 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.Current, top); + 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); + + ((FakeDriver)Application.Driver).SetBufferSize (30, 20); + 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); + 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 (-7, -5), 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 (-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 (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 (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 (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 (16, -2), 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 033b72cc1f..7d5d044081 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); @@ -903,9 +903,8 @@ 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 () + public void Draw_A_ContextMenu_Over_A_Dialog () { var top = Application.Top; var win = new Window (); @@ -983,5 +982,163 @@ public void Draw_A_ContextManu_Over_A_Dialog () Application.End (rs); } + + [Fact, AutoInitShutdown] + 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); + + 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); + Assert.Equal (dialog, Application.Top); + 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); + } + + [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 abf39ecd27..fed55bf986 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); @@ -868,14 +868,14 @@ 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 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); @@ -954,8 +954,8 @@ public void UseSubMenusSingleFrame_True_By_Mouse () 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 ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) }), new MenuItem ("Three", "", null), }) @@ -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.Draw (); + 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.Draw (); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│┌───────────┐ │ +│ └─────────┘│ All │ │ +│ │ Selected │ │ +│ └───────────┘ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + top.Draw (); + 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); @@ -1738,71 +1824,239 @@ public void MenuBar_In_Window_Without_Other_Views () } [Fact, AutoInitShutdown] - public void AllowNullChecked_Get_Set () + public void MenuBar_In_Window_Without_Other_Views_Without_Top_Init () { - var mi = new MenuItem ("Check this out 你", "", null) { - CheckType = MenuItemCheckStyle.Checked - }; - mi.Action = mi.ToggleChecked; + var win = new Window (); var menu = new MenuBar (new MenuBarItem [] { - new MenuBarItem("Nullable Checked",new MenuItem [] { - mi + 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) + }) }) }); - new CheckBox (); - var top = Application.Top; - top.Add (menu); - Application.Begin (top); + win.Add (menu); + ((FakeDriver)Application.Driver).SetBufferSize (40, 8); + Application.Begin (win); - Assert.False (mi.Checked); - Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); - Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ()))); - Application.MainLoop.RunIteration (); - Assert.True (mi.Checked); - Assert.True (menu.MouseEvent (new MouseEvent () { - X = 0, - Y = 0, - Flags = MouseFlags.Button1Pressed, - View = menu - })); - Assert.True (menu.openMenu.MouseEvent (new MouseEvent () { - X = 0, - Y = 1, - Flags = MouseFlags.Button1Clicked, - View = menu.openMenu - })); - Application.MainLoop.RunIteration (); - Assert.False (mi.Checked); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ │ +│ │ +│ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); - mi.AllowNullChecked = true; - Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); - Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ()))); - Application.MainLoop.RunIteration (); - Assert.Null (mi.Checked); - Assert.True (menu.MouseEvent (new MouseEvent () { - X = 0, - Y = 0, - Flags = MouseFlags.Button1Pressed, - View = menu - })); + Assert.True (win.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + win.Draw (); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│┌──────┐ │ +││ New │ │ +│└──────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); Application.Refresh (); TestHelpers.AssertDriverContentsWithFrameAre (@" - Nullable Checked -┌──────────────────────┐ -│ ⍰ Check this out 你 │ -└──────────────────────┘", output); - Assert.True (menu.openMenu.MouseEvent (new MouseEvent () { - X = 0, - Y = 1, - Flags = MouseFlags.Button1Clicked, - View = menu.openMenu - })); - Application.MainLoop.RunIteration (); - Assert.True (mi.Checked); - Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); - Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ()))); - Application.MainLoop.RunIteration (); - Assert.False (mi.Checked); +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│ │ +│ └─────────┘ │ +│ │ +│ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + win.Draw (); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│┌───────────┐ │ +│ └─────────┘│ All │ │ +│ │ Selected │ │ +│ └───────────┘ │ +└──────────────────────────────────────┘", output); + + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + win.Draw (); + 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.Draw (); + 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.Draw (); + TestHelpers.AssertDriverContentsWithFrameAre (@" +┌──────────────────────────────────────┐ +│ File Edit │ +│ ┌─────────┐ │ +│ │ Delete ►│┌───────────┐ │ +│ └─────────┘│ All │ │ +│ │ Selected │ │ +│ └───────────┘ │ +└──────────────────────────────────────┘", output); + + Assert.True (((MenuBar)top.Subviews [0]).openMenu.ProcessKey (new KeyEvent (Key.CursorRight, new KeyModifiers ()))); + top.Draw (); + 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 () + { + var mi = new MenuItem ("Check this out 你", "", null) { + CheckType = MenuItemCheckStyle.Checked + }; + mi.Action = mi.ToggleChecked; + var menu = new MenuBar (new MenuBarItem [] { + new MenuBarItem("Nullable Checked",new MenuItem [] { + mi + }) + }); + new CheckBox (); + var top = Application.Top; + top.Add (menu); + Application.Begin (top); + + Assert.False (mi.Checked); + Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ()))); + Application.MainLoop.RunIteration (); + Assert.True (mi.Checked); + Assert.True (menu.MouseEvent (new MouseEvent () { + X = 0, + Y = 0, + Flags = MouseFlags.Button1Pressed, + View = menu + })); + Assert.True (menu.openMenu.MouseEvent (new MouseEvent () { + X = 0, + Y = 1, + Flags = MouseFlags.Button1Clicked, + View = menu.openMenu + })); + Application.MainLoop.RunIteration (); + Assert.False (mi.Checked); + + mi.AllowNullChecked = true; + Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ()))); + Application.MainLoop.RunIteration (); + Assert.Null (mi.Checked); + Assert.True (menu.MouseEvent (new MouseEvent () { + X = 0, + Y = 0, + Flags = MouseFlags.Button1Pressed, + View = menu + })); + Application.Refresh (); + TestHelpers.AssertDriverContentsWithFrameAre (@" + Nullable Checked +┌──────────────────────┐ +│ ⍰ Check this out 你 │ +└──────────────────────┘", output); + Assert.True (menu.openMenu.MouseEvent (new MouseEvent () { + X = 0, + Y = 1, + Flags = MouseFlags.Button1Clicked, + View = menu.openMenu + })); + Application.MainLoop.RunIteration (); + Assert.True (mi.Checked); + Assert.True (menu.ProcessHotKey (new KeyEvent (Key.F9, new KeyModifiers ()))); + Assert.True (menu.openMenu.ProcessKey (new KeyEvent (Key.Enter, new KeyModifiers ()))); + Application.MainLoop.RunIteration (); + Assert.False (mi.Checked); Assert.True (menu.MouseEvent (new MouseEvent () { X = 0, Y = 0, @@ -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); @@ -1870,10 +2124,10 @@ 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] @@ -1881,10 +2135,10 @@ 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) + new MenuItem ("One", "", null), + new MenuItem ("Two", "", null) }) - }) { MenusBorderStyle = LineStyle.None }; + }) { 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,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), - }) + 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); @@ -1987,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); } @@ -2012,10 +2265,10 @@ public void UseSubMenusSingleFrame_True_Disabled_Border () 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 ("Sub-Menu 1", "", null), + new MenuItem ("Sub-Menu 2", "", null) }), - new MenuItem ("Three", "", null), + new MenuItem ("Three", "", null), }) }) { MenusBorderStyle = LineStyle.None }; @@ -2033,9 +2286,8 @@ public void UseSubMenusSingleFrame_True_Disabled_Border () var expected = @" Numbers One - Two ► - Three -"; + Two ► + Three "; _ = TestHelpers.AssertDriverContentsWithFrameAre (expected, output); @@ -2043,14 +2295,405 @@ 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); } + + [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 = 4, + 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 = 4 + 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); + } + + [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); + } + + [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); + } } }