This document specifies the current behavior of context menus in XenoAtom.Terminal.UI as implemented.
For end-user usage and examples, see Context menus.
This spec focuses on the concrete behavior of context menus (the fullscreen popup menu opened by right-click).
Visual.ContextMenuFactoryCommandPresentation.ContextMenu)Terminal.Live(...)) (not supported).ContextMenu control type (current implementation is a service + popup host).Visual.ContextMenuFactoryFunc<Visual, IEnumerable<MenuItem>>? ContextMenuFactory { get; set; }ContextMenuServicePopup Show(Visual target, IEnumerable<MenuItem> items, int uiX, int uiY)
TerminalApp is running.TerminalMouseButton.Right) triggers the context menu behavior.src/XenoAtom.Terminal.UI/Controls/ContextMenuService.cssrc/XenoAtom.Terminal.UI/TerminalApp.cs (TryShowContextMenu / ShowContextMenu)src/XenoAtom.Terminal.UI/Controls/MenuItem.cssrc/XenoAtom.Terminal.UI/Styling/MenuListStyle.cssrc/XenoAtom.Terminal.UI/Styling/PopupStyle.cssrc/XenoAtom.Terminal.UI.Tests/ContextMenuTests.cssamples/ControlsDemo/Demos/ContextMenuDemo.csWhen opening a context menu for a hovered target hitTarget:
hitTarget → Parent → … and uses the first visual with a non-null ContextMenuFactory.CommandPresentation.ContextMenu via CommandQuery.MenuItem whose header is new Markup(cmd.LabelMarkup) and whose CommandTarget is the visual that registered the command.Menu item execution uses a “target” visual:
MenuItem.CommandTarget (when set) wins.hitTarget.The effective target is passed to:
Command.IsVisibleFor(target)Command.CanExecuteFor(target)Command.Execute(target)Context menus are rendered by an internal ContextMenuList visual hosted inside a Popup.
MenuListStyle.Padding around the content.1.padding.Horizontal + max(rowWidth) + submenuColumnWidthpadding.Vertical + items.CountsubmenuColumnWidth is 0 unless at least one item has a visible submenu, in which case the list reserves a right-side column wide enough to draw MenuListStyle.SubmenuGlyph plus spacing.innerRect.Width - submenuColumnWidth
(so submenu arrows never overlap the item content).For each row, the list fills the row area with:
MenuListStyle.ResolveSeparatorStyle(theme) for separatorsMenuListStyle.ResolveItemStyle(theme, enabled, selected, hovered) for regular itemstheme.Lines.Horizontal (dimmed via the separator style).IsVisibleFor(target)), the submenu glyph (› by default) is drawn in the reserved submenu column and rendered with TextStyle.Dim.The list is focusable and supports both keyboard and mouse interaction.
Up / Down: move selection to the previous/next selectable item; closes any open submenu.Enter / Space: invoke selected item (or open submenu if it has one).Right: open submenu for selected item (when present).Left:
Escape: closes the root popup.Popup instances with:
Placement = PopupPlacement.RightAnchor = rowVisualMenuItem.IsVisibleFor(target)).Popup).AnchorRect = (uiX, uiY, 1, 1)Placement = BelowMatchAnchorWidth = falseCloseOnTab = truePopupStyle.Padding = 0 (chrome is provided by the MenuListStyle.PopupTemplateFactory wrapper)Context menus reuse the menu list styling:
MenuListStyle controls spacing, padding, glyphs, and per-state styles (normal/selected/hovered/disabled/separator).MenuListStyle.PopupTemplateFactory controls the “chrome” around the list when shown in a popup.
Group.MenuListStyle.NoBorder disables the wrapper.ContextMenuTests verifies:
ContextMenuFactory when providedCommandPresentation.ContextMenu) when no factory is presentContextMenuDemo shows both command-based and factory-based menus, and uses ContextMenuService.Show(...) for screenshots.MenuItem.IsVisibleFor(target); factories should return only the items they want to display.IsVisibleFor(target) for consistency with submenus.Shift+F10) when supported by the terminal input layer.