| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750 |
- namespace Terminal.Gui.Views;
- /// <summary>
- /// A <see cref="PopoverBaseImpl"/>-derived view that provides a cascading menu.
- /// Can be used as a context menu or a drop-down menu as part of <see cref="MenuBar"/>.
- /// </summary>
- /// <remarks>
- /// <para>
- /// <b>IMPORTANT:</b> Must be registered with <see cref="Application.Popover"/> via
- /// <see cref="ApplicationPopover.Register"/> before calling <see cref="MakeVisible"/> or
- /// <see cref="ApplicationPopover.Show"/>.
- /// </para>
- /// <para>
- /// <b>Usage Example:</b>
- /// </para>
- /// <code>
- /// var menu = new PopoverMenu ([
- /// new MenuItem ("Cut", Command.Cut),
- /// new MenuItem ("Copy", Command.Copy),
- /// new MenuItem ("Paste", Command.Paste)
- /// ]);
- /// Application.Popover?.Register (menu);
- /// menu.MakeVisible (); // or Application.Popover?.Show (menu);
- /// </code>
- /// <para>
- /// See <see cref="PopoverBaseImpl"/> and <see cref="IPopover"/> for lifecycle, focus, and keyboard handling details.
- /// </para>
- /// </remarks>
- public class PopoverMenu : PopoverBaseImpl, IDesignable
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="PopoverMenu"/> class.
- /// </summary>
- public PopoverMenu () : this ((Menu?)null) { }
- /// <summary>
- /// Initializes a new instance of the <see cref="PopoverMenu"/> class. If any of the elements of
- /// <paramref name="menuItems"/> is <see langword="null"/>, a <see cref="Line"/> will be created instead.
- /// </summary>
- /// <param name="menuItems">The views to use as menu items. Null elements become separator lines.</param>
- /// <remarks>
- /// Remember to call <see cref="ApplicationPopover.Register"/> before calling <see cref="MakeVisible"/>.
- /// </remarks>
- public PopoverMenu (IEnumerable<View>? menuItems) : this (
- new Menu (menuItems?.Select (item => item ?? new Line ()))
- {
- Title = "Popover Root"
- })
- { }
- /// <summary>
- /// Initializes a new instance of the <see cref="PopoverMenu"/> class with the specified menu items.
- /// </summary>
- /// <param name="menuItems">The menu items to display in the popover.</param>
- /// <remarks>
- /// Remember to call <see cref="ApplicationPopover.Register"/> before calling <see cref="MakeVisible"/>.
- /// </remarks>
- public PopoverMenu (IEnumerable<MenuItem>? menuItems) : this (
- new Menu (menuItems)
- {
- Title = "Popover Root"
- })
- { }
- /// <summary>
- /// Initializes a new instance of the <see cref="PopoverMenu"/> class with the specified root <see cref="Menu"/>.
- /// </summary>
- /// <param name="root">The root menu that contains the top-level menu items.</param>
- /// <remarks>
- /// Remember to call <see cref="ApplicationPopover.Register"/> before calling <see cref="MakeVisible"/>.
- /// </remarks>
- public PopoverMenu (Menu? root)
- {
- // Do this to support debugging traces where Title gets set
- base.HotKeySpecifier = (Rune)'\xffff';
- if (Border is { })
- {
- Border.Settings &= ~BorderSettings.Title;
- }
- Key = DefaultKey;
- base.Visible = false;
- Root = root;
- AddCommand (Command.Right, MoveRight);
- KeyBindings.Add (Key.CursorRight, Command.Right);
- AddCommand (Command.Left, MoveLeft);
- KeyBindings.Add (Key.CursorLeft, Command.Left);
- // PopoverBaseImpl sets a key binding for Quit, so we
- // don't need to do it here.
- AddCommand (Command.Quit, Quit);
- return;
- bool? Quit (ICommandContext? ctx)
- {
- // Logging.Debug ($"{Title} Command.Quit - {ctx?.Source?.Title}");
- if (!Visible)
- {
- // If we're not visible, the command is not for us
- return false;
- }
- // This ensures the quit command gets propagated to the owner of the popover.
- // This is important for MenuBarItems to ensure the MenuBar loses focus when
- // the user presses QuitKey to cause the menu to close.
- // Note, we override OnAccepting, which will set Visible to false
- // Logging.Debug ($"{Title} Command.Quit - Calling RaiseAccepting {ctx?.Source?.Title}");
- bool? ret = RaiseAccepting (ctx);
- if (Visible && ret is not true)
- {
- Visible = false;
- return true;
- }
- // If we are Visible, returning true will stop the QuitKey from propagating
- // If we are not Visible, returning false will allow the QuitKey to propagate
- return Visible;
- }
- bool? MoveLeft (ICommandContext? ctx)
- {
- if (Focused == Root)
- {
- return false;
- }
- if (MostFocused is MenuItem { SuperView: Menu focusedMenu })
- {
- focusedMenu.SuperMenuItem?.SetFocus ();
- return true;
- }
- return AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop);
- }
- bool? MoveRight (ICommandContext? ctx)
- {
- if (MostFocused is MenuItem { SubMenu.Visible: true } focused)
- {
- focused.SubMenu.SetFocus ();
- return true;
- }
- return false;
- }
- }
- private Key _key = DefaultKey;
- /// <summary>
- /// Gets or sets the key that will activate the popover menu when it is registered but not visible.
- /// </summary>
- /// <remarks>
- /// This key binding works as a global hotkey when the popover is registered with
- /// <see cref="Application.Popover"/>. The default value is <see cref="DefaultKey"/> (<see cref="Key.F10"/> with
- /// Shift).
- /// </remarks>
- public Key Key
- {
- get => _key;
- set
- {
- Key oldKey = _key;
- _key = value;
- KeyChanged?.Invoke (this, new (oldKey, _key));
- }
- }
- /// <summary>
- /// Raised when the <see cref="Key"/> property is changed.
- /// </summary>
- public event EventHandler<KeyChangedEventArgs>? KeyChanged;
- /// <summary>
- /// Gets or sets the default key for activating popover menus. The default value is <see cref="Key.F10"/> with Shift.
- /// </summary>
- /// <remarks>
- /// This is a configuration property that affects all new <see cref="PopoverMenu"/> instances.
- /// </remarks>
- [ConfigurationProperty (Scope = typeof (SettingsScope))]
- public static Key DefaultKey { get; set; } = Key.F10.WithShift;
- /// <summary>
- /// The mouse flags that will cause the popover menu to be visible. The default is
- /// <see cref="MouseFlags.Button3Clicked"/> which is typically the right mouse button.
- /// </summary>
- public MouseFlags MouseFlags { get; set; } = MouseFlags.Button3Clicked;
- /// <summary>
- /// Makes the popover menu visible and locates it at <paramref name="idealScreenPosition"/>. The actual position of the
- /// menu will be adjusted to ensure the menu fully fits on the screen, with the mouse cursor positioned over
- /// the first cell of the first <see cref="MenuItem"/>.
- /// </summary>
- /// <param name="idealScreenPosition">
- /// The ideal screen-relative position for the menu. If <see langword="null"/>, the current mouse position will be
- /// used.
- /// </param>
- /// <remarks>
- /// <para>
- /// IMPORTANT: The popover must be registered with <see cref="Application.Popover"/> before calling this
- /// method.
- /// Call <see cref="ApplicationPopover.Register"/> first.
- /// </para>
- /// <para>
- /// This method internally calls <see cref="ApplicationPopover.Show"/>, which will throw
- /// <see cref="InvalidOperationException"/> if the popover is not registered.
- /// </para>
- /// </remarks>
- /// <exception cref="InvalidOperationException">Thrown if the popover has not been registered.</exception>
- public void MakeVisible (Point? idealScreenPosition = null)
- {
- if (Visible)
- {
- // Logging.Debug ($"{Title} - Already Visible");
- return;
- }
- UpdateKeyBindings ();
- SetPosition (idealScreenPosition);
- App!.Popover?.Show (this);
- }
- /// <summary>
- /// Sets the position of the popover menu at <paramref name="idealScreenPosition"/>. The actual position will be
- /// adjusted to ensure the menu fully fits on the screen, with the mouse cursor positioned over the first cell of
- /// the first <see cref="MenuItem"/> (if possible).
- /// </summary>
- /// <param name="idealScreenPosition">
- /// The ideal screen-relative position for the menu. If <see langword="null"/>, the current mouse position will be
- /// used.
- /// </param>
- /// <remarks>
- /// This method only sets the position; it does not make the popover visible. Use <see cref="MakeVisible"/> to
- /// both position and show the popover.
- /// </remarks>
- public void SetPosition (Point? idealScreenPosition = null)
- {
- idealScreenPosition ??= App?.Mouse.LastMousePosition;
- if (idealScreenPosition is null || Root is null)
- {
- return;
- }
- Point pos = idealScreenPosition.Value;
- if (!Root.IsInitialized)
- {
- Root.App ??= App;
- Root.BeginInit ();
- Root.EndInit ();
- Root.Layout ();
- }
- pos = GetMostVisibleLocationForSubMenu (Root, pos);
- Root.X = pos.X;
- Root.Y = pos.Y;
- }
- /// <inheritdoc/>
- /// <remarks>
- /// When becoming visible, the root menu is added and shown. When becoming hidden, the root menu is removed
- /// and the popover is hidden via <see cref="ApplicationPopover.Hide"/>.
- /// </remarks>
- protected override void OnVisibleChanged ()
- {
- // Logging.Debug ($"{Title} - Visible: {Visible}");
- base.OnVisibleChanged ();
- if (Visible)
- {
- AddAndShowSubMenu (_root);
- }
- else
- {
- HideAndRemoveSubMenu (_root);
- App?.Popover?.Hide (this);
- }
- }
- private Menu? _root;
- /// <summary>
- /// Gets or sets the <see cref="Menu"/> that is the root of the popover menu hierarchy.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The root menu contains the top-level menu items. Setting this property updates key bindings and
- /// event subscriptions for all menus in the hierarchy.
- /// </para>
- /// <para>
- /// When set, all submenus are configured with appropriate event handlers for selection and acceptance.
- /// </para>
- /// </remarks>
- public Menu? Root
- {
- get => _root;
- set
- {
- if (_root == value)
- {
- return;
- }
- HideAndRemoveSubMenu (_root);
- _root = value;
- if (_root is { })
- {
- _root.App = App;
- }
- // TODO: This needs to be done whenever any MenuItem in the menu tree changes to support dynamic menus
- // TODO: And it needs to clear the old bindings first
- UpdateKeyBindings ();
- // TODO: This needs to be done whenever any MenuItem in the menu tree changes to support dynamic menus
- IEnumerable<Menu> allMenus = GetAllSubMenus ();
- foreach (Menu menu in allMenus)
- {
- menu.App = App;
- menu.Visible = false;
- menu.Accepting += MenuOnAccepting;
- menu.Accepted += MenuAccepted;
- menu.SelectedMenuItemChanged += MenuOnSelectedMenuItemChanged;
- }
- }
- }
- private void UpdateKeyBindings ()
- {
- IEnumerable<MenuItem> all = GetMenuItemsOfAllSubMenus ();
- foreach (MenuItem menuItem in all.Where (mi => mi.Command != Command.NotBound))
- {
- Key? key;
- if (menuItem.TargetView is { })
- {
- // A TargetView implies HotKey
- key = menuItem.TargetView.HotKeyBindings.GetFirstFromCommands (menuItem.Command);
- }
- else
- {
- // No TargetView implies Application HotKey
- key = App?.Keyboard.KeyBindings.GetFirstFromCommands (menuItem.Command);
- }
- if (key is not { IsValid: true })
- {
- continue;
- }
- if (menuItem.Key.IsValid)
- {
- //Logging.Warning ("Do not specify a Key for MenuItems where a Command is specified. Key will be determined automatically.");
- }
- menuItem.Key = key;
- // Logging.Debug ($"{Title} - HotKey: {menuItem.Key}->{menuItem.Command}");
- }
- }
- /// <inheritdoc/>
- /// <remarks>
- /// This method checks all menu items in the hierarchy for a matching key binding and invokes the
- /// appropriate menu item if found.
- /// </remarks>
- protected override bool OnKeyDownNotHandled (Key key)
- {
- // See if any of our MenuItems have this key as Key
- IEnumerable<MenuItem> all = GetMenuItemsOfAllSubMenus ();
- foreach (MenuItem menuItem in all)
- {
- if (key != Application.QuitKey && menuItem.Key == key)
- {
- // Logging.Debug ($"{Title} - key: {key}");
- return menuItem.NewKeyDownEvent (key);
- }
- }
- return base.OnKeyDownNotHandled (key);
- }
- /// <summary>
- /// Gets all the submenus in the popover menu hierarchy, including the root menu.
- /// </summary>
- /// <returns>An enumerable collection of all <see cref="Menu"/> instances in the hierarchy.</returns>
- /// <remarks>
- /// This method performs a depth-first traversal of the menu tree, starting from <see cref="Root"/>.
- /// </remarks>
- public IEnumerable<Menu> GetAllSubMenus ()
- {
- List<Menu> result = [];
- if (Root == null)
- {
- return result;
- }
- Stack<Menu> stack = new ();
- stack.Push (Root);
- while (stack.Count > 0)
- {
- Menu currentMenu = stack.Pop ();
- result.Add (currentMenu);
- foreach (View subView in currentMenu.SubViews)
- {
- if (subView is MenuItem { SubMenu: { } } menuItem)
- {
- stack.Push (menuItem.SubMenu);
- }
- }
- }
- return result;
- }
- /// <summary>
- /// Gets all the menu items in the popover menu hierarchy.
- /// </summary>
- /// <returns>An enumerable collection of all <see cref="MenuItem"/> instances across all menus in the hierarchy.</returns>
- /// <remarks>
- /// This method traverses all menus returned by <see cref="GetAllSubMenus"/> and collects their menu items.
- /// </remarks>
- internal IEnumerable<MenuItem> GetMenuItemsOfAllSubMenus ()
- {
- List<MenuItem> result = [];
- foreach (Menu menu in GetAllSubMenus ())
- {
- foreach (View subView in menu.SubViews)
- {
- if (subView is MenuItem menuItem)
- {
- result.Add (menuItem);
- }
- }
- }
- return result;
- }
- /// <summary>
- /// Shows the submenu of the specified <see cref="MenuItem"/>, if it has one.
- /// </summary>
- /// <param name="menuItem">The menu item whose submenu should be shown.</param>
- /// <remarks>
- /// <para>
- /// If another submenu is currently visible at the same level, it will be hidden before showing the new one.
- /// </para>
- /// <para>
- /// The submenu is positioned to the right of the menu item, adjusted to ensure full visibility on screen.
- /// </para>
- /// </remarks>
- internal void ShowSubMenu (MenuItem? menuItem)
- {
- var menu = menuItem?.SuperView as Menu;
- // Logging.Debug ($"{Title} - menuItem: {menuItem?.Title}, menu: {menu?.Title}");
- menu?.Layout ();
- // If there's a visible peer, remove / hide it
- if (menu?.SubViews.FirstOrDefault (v => v is MenuItem { SubMenu.Visible: true }) is MenuItem visiblePeer)
- {
- HideAndRemoveSubMenu (visiblePeer.SubMenu);
- visiblePeer.ForceFocusColors = false;
- }
- if (menuItem is { SubMenu: { Visible: false } })
- {
- AddAndShowSubMenu (menuItem.SubMenu);
- Point idealLocation = ScreenToViewport (
- new (
- menuItem.FrameToScreen ().Right - menuItem.SubMenu.GetAdornmentsThickness ().Left,
- menuItem.FrameToScreen ().Top - menuItem.SubMenu.GetAdornmentsThickness ().Top));
- Point pos = GetMostVisibleLocationForSubMenu (menuItem.SubMenu, idealLocation);
- menuItem.SubMenu.X = pos.X;
- menuItem.SubMenu.Y = pos.Y;
- menuItem.ForceFocusColors = true;
- }
- }
- /// <summary>
- /// Calculates the most visible screen-relative location for the specified <paramref name="menu"/>.
- /// </summary>
- /// <param name="menu">The menu to position.</param>
- /// <param name="idealLocation">The ideal screen-relative location.</param>
- /// <returns>The adjusted screen-relative position that ensures maximum visibility of the menu.</returns>
- /// <remarks>
- /// This method adjusts the position to keep the menu fully visible on screen, considering screen boundaries.
- /// </remarks>
- internal Point GetMostVisibleLocationForSubMenu (Menu menu, Point idealLocation)
- {
- var pos = Point.Empty;
- // Calculate the initial position to the right of the menu item
- GetLocationEnsuringFullVisibility (
- menu,
- idealLocation.X,
- idealLocation.Y,
- out int nx,
- out int ny);
- return new (nx, ny);
- }
- private void AddAndShowSubMenu (Menu? menu)
- {
- if (menu is { SuperView: null, Visible: false })
- {
- // Logging.Debug ($"{Title} ({menu?.Title}) - menu.Visible: {menu?.Visible}");
- // TODO: Find the menu item below the mouse, if any, and select it
- if (!menu!.IsInitialized)
- {
- menu.App ??= App;
- menu.BeginInit ();
- menu.EndInit ();
- }
- menu.ClearFocus ();
- base.Add (menu);
- // IMPORTANT: This must be done after adding the menu to the super view or Add will try
- // to set focus to it.
- menu.Visible = true;
- menu.Layout ();
- }
- }
- private void HideAndRemoveSubMenu (Menu? menu)
- {
- if (menu is { Visible: true })
- {
- // Logging.Debug ($"{Title} ({menu?.Title}) - menu.Visible: {menu?.Visible}");
- // If there's a visible submenu, remove / hide it
- if (menu.SubViews.FirstOrDefault (v => v is MenuItem { SubMenu.Visible: true }) is MenuItem visiblePeer)
- {
- HideAndRemoveSubMenu (visiblePeer.SubMenu);
- visiblePeer.ForceFocusColors = false;
- }
- menu.Visible = false;
- menu.ClearFocus ();
- base.Remove (menu);
- if (menu == Root)
- {
- Visible = false;
- }
- }
- }
- private void MenuOnAccepting (object? sender, CommandEventArgs e)
- {
- var senderView = sender as View;
- // Logging.Debug ($"{Title} ({e.Context?.Source?.Title}) Command: {e.Context?.Command} - Sender: {senderView?.GetType ().Name}");
- if (e.Context?.Command != Command.HotKey)
- {
- // Logging.Debug ($"{Title} - Setting Visible = false");
- Visible = false;
- }
- if (e.Context is CommandContext<KeyBinding> keyCommandContext)
- {
- if (keyCommandContext.Binding.Key is { } && keyCommandContext.Binding.Key == Application.QuitKey && SuperView is { Visible: true })
- {
- // Logging.Debug ($"{Title} - Setting e.Handled = true - Application.QuitKey/Command = Command.Quit");
- e.Handled = true;
- }
- }
- }
- private void MenuAccepted (object? sender, CommandEventArgs e)
- {
- // Logging.Debug ($"{Title} ({e.Context?.Source?.Title}) Command: {e.Context?.Command}");
- if (e.Context?.Source is MenuItem { SubMenu: null })
- {
- HideAndRemoveSubMenu (_root);
- }
- else if (e.Context?.Source is MenuItem { SubMenu: { } } menuItemWithSubMenu)
- {
- ShowSubMenu (menuItemWithSubMenu);
- }
- RaiseAccepted (e.Context);
- }
- /// <inheritdoc/>
- /// <remarks>
- /// <para>
- /// When the popover is not visible, only hotkey commands are processed.
- /// </para>
- /// <para>
- /// This method raises <see cref="View.Accepted"/> for commands that originate from menu items in the hierarchy.
- /// </para>
- /// </remarks>
- protected override bool OnAccepting (CommandEventArgs args)
- {
- // Logging.Debug ($"{Title} ({args.Context?.Source?.Title}) Command: {args.Context?.Command}");
- // If we're not visible, ignore any keys that are not hotkeys
- CommandContext<KeyBinding>? keyCommandContext = args.Context as CommandContext<KeyBinding>? ?? default (CommandContext<KeyBinding>);
- if (!Visible && keyCommandContext is { Binding.Key: { } })
- {
- if (GetMenuItemsOfAllSubMenus ().All (i => i.Key != keyCommandContext.Value.Binding.Key))
- {
- // Logging.Debug ($"{Title} ({args.Context?.Source?.Title}) Command: {args.Context?.Command} - ignore any keys that are not hotkeys");
- return false;
- }
- }
- // Logging.Debug ($"{Title} - calling base.OnAccepting: {args.Context?.Command}");
- bool? ret = base.OnAccepting (args);
- if (ret is true || args.Handled)
- {
- return args.Handled = true;
- }
- // Only raise Accepted if the command came from one of our MenuItems
- //if (GetMenuItemsOfAllSubMenus ().Contains (args.Context?.Source))
- {
- // Logging.Debug ($"{Title} - Calling RaiseAccepted {args.Context?.Command}");
- RaiseAccepted (args.Context);
- }
- // Always return false to enable accepting to continue propagating
- return false;
- }
- private void MenuOnSelectedMenuItemChanged (object? sender, MenuItem? e)
- {
- // Logging.Debug ($"{Title} - e.Title: {e?.Title}");
- ShowSubMenu (e);
- }
- /// <inheritdoc/>
- /// <exception cref="InvalidOperationException">
- /// Thrown if attempting to add a <see cref="Menu"/> or <see cref="MenuItem"/> directly to the popover.
- /// </exception>
- /// <remarks>
- /// Do not add <see cref="MenuItem"/> or <see cref="Menu"/> views directly to the popover.
- /// Use the <see cref="Root"/> property instead.
- /// </remarks>
- protected override void OnSubViewAdded (View view)
- {
- if (Root is null && (view is Menu || view is MenuItem))
- {
- throw new InvalidOperationException ("Do not add MenuItems or Menus directly to a PopoverMenu. Use the Root property.");
- }
- base.OnSubViewAdded (view);
- }
- /// <inheritdoc/>
- /// <remarks>
- /// This method unsubscribes from all menu events and disposes the root menu.
- /// </remarks>
- protected override void Dispose (bool disposing)
- {
- if (disposing)
- {
- IEnumerable<Menu> allMenus = GetAllSubMenus ();
- foreach (Menu menu in allMenus)
- {
- menu.Accepting -= MenuOnAccepting;
- menu.Accepted -= MenuAccepted;
- menu.SelectedMenuItemChanged -= MenuOnSelectedMenuItemChanged;
- }
- _root?.Dispose ();
- _root = null;
- }
- base.Dispose (disposing);
- }
- /// <summary>
- /// Enables the popover menu for use in design-time scenarios.
- /// </summary>
- /// <typeparam name="TContext">The type of the target view context.</typeparam>
- /// <param name="targetView">The target view to associate with the menu commands.</param>
- /// <returns><see langword="true"/> if successfully enabled for design; otherwise, <see langword="false"/>.</returns>
- /// <remarks>
- /// This method creates a default set of menu items (Cut, Copy, Paste, Select All, Quit) for design-time use.
- /// It is primarily used for demonstration and testing purposes.
- /// </remarks>
- public bool EnableForDesign<TContext> (ref TContext targetView) where TContext : notnull
- {
- // Note: This menu is used by unit tests. If you modify it, you'll likely have to update
- // unit tests.
- Root = new (
- [
- new MenuItem (targetView as View, Command.Cut),
- new MenuItem (targetView as View, Command.Copy),
- new MenuItem (targetView as View, Command.Paste),
- new Line (),
- new MenuItem (targetView as View, Command.SelectAll),
- new Line (),
- new MenuItem (targetView as View, Command.Quit)
- ])
- {
- Title = "Popover Demo Root"
- };
- // NOTE: This is a workaround for the fact that the PopoverMenu is not visible in the designer
- // NOTE: without being activated via App?.Popover. But we want it to be visible.
- // NOTE: If you use PopoverView.EnableForDesign for real Popover scenarios, change back to false
- // NOTE: after calling EnableForDesign.
- //Visible = true;
- return true;
- }
- }
|