#nullable enable namespace Terminal.Gui; /// /// is a menu item on . MenuBarItems do not support /// . /// public class MenuBarItem : MenuItem { /// Initializes a new as a . /// Title for the menu item. /// Help text to display. Will be displayed next to the Title surrounded by parentheses. /// Action to invoke when the menu item is activated. /// Function to determine if the action can currently be executed. /// The parent of this if any. public MenuBarItem ( string title, string help, Action action, Func? canExecute = null, MenuItem? parent = null ) : base (title, help, action, canExecute, parent) { SetInitialProperties (title, null, null, true); } /// Initializes a new . /// Title for the menu item. /// The items in the current menu. /// The parent of this if any. public MenuBarItem (string title, MenuItem [] children, MenuItem? parent = null) { SetInitialProperties (title, children, parent); } /// Initializes a new with separate list of items. /// Title for the menu item. /// The list of items in the current menu. /// The parent of this if any. public MenuBarItem (string title, List children, MenuItem? parent = null) { SetInitialProperties (title, children, parent); } /// Initializes a new . /// The items in the current menu. public MenuBarItem (MenuItem [] children) : this ("", children) { } /// Initializes a new . public MenuBarItem () : this ([]) { } /// /// Gets or sets an array of objects that are the children of this /// /// /// The children. public MenuItem? []? Children { get; set; } internal bool IsTopLevel => Parent is null && (Children is null || Children.Length == 0) && Action != null; /// Get the index of a child . /// /// Returns a greater than -1 if the is a child. public int GetChildrenIndex (MenuItem children) { var i = 0; if (Children is null) { return -1; } foreach (MenuItem? child in Children) { if (child == children) { return i; } i++; } return -1; } /// Check if a is a submenu of this MenuBar. /// /// Returns true if it is a submenu. false otherwise. public bool IsSubMenuOf (MenuItem menuItem) { return Children!.Any (child => child == menuItem && child.Parent == menuItem.Parent); } /// Check if a is a . /// /// Returns a or null otherwise. public MenuBarItem? SubMenu (MenuItem? menuItem) { return menuItem as MenuBarItem; } internal void AddShortcutKeyBindings (MenuBar menuBar) { if (Children is null) { return; } _menuBar = menuBar; IEnumerable menuItems = Children.Where (m => m is { })!; foreach (MenuItem menuItem in menuItems) { // Initialize MenuItem _menuBar menuItem._menuBar = menuBar; // For MenuBar only add shortcuts for submenus if (menuItem.ShortcutKey != Key.Empty) { menuItem.AddShortcutKeyBinding (menuBar, Key.Empty); } SubMenu (menuItem)?.AddShortcutKeyBindings (menuBar); } } // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local private void SetInitialProperties (string title, object? children, MenuItem? parent = null, bool isTopLevel = false) { if (!isTopLevel && children is null) { throw new ArgumentNullException ( nameof (children), @"The parameter cannot be null. Use an empty array instead." ); } SetTitle (title); if (parent is { }) { Parent = parent; } switch (children) { case List childrenList: { MenuItem [] newChildren = []; foreach (MenuItem [] grandChild in childrenList) { foreach (MenuItem child in grandChild) { SetParent (grandChild); Array.Resize (ref newChildren, newChildren.Length + 1); newChildren [^1] = child; } } Children = newChildren; break; } case MenuItem [] items: SetParent (items); Children = items; break; default: Children = null; break; } } private void SetParent (MenuItem [] children) { foreach (MenuItem child in children) { if (child is { Parent: null }) { child.Parent = this; } } } private void SetTitle (string? title) { title ??= string.Empty; Title = title; } /// /// Add a dynamically into the .Menus. /// /// /// public void AddMenuBarItem (MenuBar menuBar, MenuItem? menuItem = null) { ArgumentNullException.ThrowIfNull (menuBar); _menuBar = menuBar; if (menuItem is null) { MenuBarItem [] menus = _menuBar.Menus; Array.Resize (ref menus, menus.Length + 1); menus [^1] = this; _menuBar.Menus = menus; } else { MenuItem [] childrens = (Children ?? [])!; Array.Resize (ref childrens, childrens.Length + 1); menuItem._menuBar = menuBar; childrens [^1] = menuItem; Children = childrens; } } /// public override void RemoveMenuItem () { if (Children is { }) { foreach (MenuItem? menuItem in Children) { if (menuItem?.ShortcutKey != Key.Empty) { // Remove an existent ShortcutKey _menuBar?.KeyBindings.Remove (menuItem?.ShortcutKey!); } } } if (ShortcutKey != Key.Empty) { // Remove an existent ShortcutKey _menuBar?.KeyBindings.Remove (ShortcutKey!); } var index = _menuBar!.Menus.IndexOf (this); if (index > -1) { if (_menuBar.Menus [index].HotKey != Key.Empty) { // Remove an existent HotKey _menuBar.KeyBindings.Remove (HotKey!.WithAlt); } _menuBar.Menus [index] = null!; } var i = 0; foreach (MenuBarItem m in _menuBar.Menus) { // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract if (m != null) { _menuBar.Menus [i] = m; i++; } } MenuBarItem [] menus = _menuBar.Menus; Array.Resize (ref menus, menus.Length - 1); _menuBar.Menus = menus; } }