PopupStack
Namespace: Hex1b
Assembly: Hex1b.dll
Manages a stack of popups for menu-like overlay behavior. Each popup has a transparent backdrop - clicking the backdrop pops that layer.
public sealed class PopupStackInheritance
Object → PopupStack
Properties
Count
Gets the number of popups currently open.
Returns: Int32
public int Count { get; }HasPopups
Gets whether any popups are currently open.
Returns: Boolean
public bool HasPopups { get; }Methods
BuildWidgets<TParent>(WidgetContext<TParent>)
Builds the ZStack widgets for all popups in the stack. Each popup is wrapped in a transparent Backdrop that calls PopToBarrier() when clicked. Anchored popups are positioned relative to their anchor node.
Parameters:
ctx(WidgetContext<<TParent>>): The widget context (typically from a ZStack).
Returns: IEnumerable<Hex1bWidget>
An enumerable of backdrop widgets for the popup stack.
public IEnumerable<Hex1bWidget> BuildWidgets<TParent>(WidgetContext<TParent> ctx) where TParent : Hex1bWidgetClear()
Clears all popups from the stack, invoking OnDismiss callbacks for each. Focus is restored to the first (bottommost) popup's FocusRestoreNode if set.
public void Clear()Pop()
Removes the topmost popup from the stack.
Returns: Boolean
True if a popup was removed, false if stack was empty.
public bool Pop()Pop(out Hex1bNode?)
Removes the topmost popup from the stack and returns the node that should receive focus.
Parameters:
focusRestoreNode(Hex1bNode): The node that was designated to receive focus when this popup was pushed, or null.
Returns: Boolean
True if a popup was removed, false if stack was empty.
public bool Pop(out Hex1bNode? focusRestoreNode)PopAtPosition(int, int)
Removes popups from the stack, stopping if the click position falls within content bounds of a lower layer (not just its backdrop).
Parameters:
x(Int32): The X coordinate of the click (screen position), or -1 to skip position check.y(Int32): The Y coordinate of the click (screen position), or -1 to skip position check.
Returns: Boolean
True if any popups were removed, false if stack was empty.
public bool PopAtPosition(int x, int y)PopToBarrier()
Removes popups from the stack until a barrier is reached or the stack is empty.
Returns: Boolean
True if any popups were removed, false if stack was empty.
public bool PopToBarrier()Push(Func<Hex1bWidget>)
Pushes a new popup onto the stack (full-screen backdrop, not anchored).
Parameters:
contentBuilder(Func<Hex1bWidget>): A function that builds the widget content for the popup.
Returns: PopupEntry
The popup entry for optional fluent configuration (e.g., .AsBarrier()).
public PopupEntry Push(Func<Hex1bWidget> contentBuilder)Push(Hex1bWidget)
Pushes a new popup onto the stack with static content (full-screen backdrop, not anchored).
Parameters:
content(Hex1bWidget): The widget content for the popup.
Returns: PopupEntry
The popup entry for optional fluent configuration (e.g., .AsBarrier()).
public PopupEntry Push(Hex1bWidget content)PushAnchored(Hex1bNode, AnchorPosition, Func<Hex1bWidget>, Hex1bNode?, Action?)
Pushes an anchored popup positioned relative to a specific node. Automatically captures theme context from ancestor ThemePanelNodes.
Parameters:
anchorNode(Hex1bNode): The node to anchor the popup to.position(AnchorPosition): Where to position the popup relative to the anchor.contentBuilder(Func<Hex1bWidget>): A function that builds the widget content for the popup.focusRestoreNode(Hex1bNode): Optional node to restore focus to when this popup is dismissed.onDismiss(Action): Optional callback invoked when this popup is dismissed to clean up owner state.
Returns: PopupEntry
The popup entry for optional fluent configuration (e.g., .AsBarrier()).
public PopupEntry PushAnchored(Hex1bNode anchorNode, AnchorPosition position, Func<Hex1bWidget> contentBuilder, Hex1bNode? focusRestoreNode = null, Action? onDismiss = null)PushAnchored(Hex1bNode, AnchorPosition, Hex1bWidget, Hex1bNode?, Action?)
Pushes an anchored popup positioned relative to a specific node.
Parameters:
anchorNode(Hex1bNode): The node to anchor the popup to.position(AnchorPosition): Where to position the popup relative to the anchor.content(Hex1bWidget): The widget content for the popup.focusRestoreNode(Hex1bNode): Optional node to restore focus to when this popup is dismissed.onDismiss(Action): Optional callback invoked when this popup is dismissed to clean up owner state.
Returns: PopupEntry
The popup entry for optional fluent configuration (e.g., .AsBarrier()).
public PopupEntry PushAnchored(Hex1bNode anchorNode, AnchorPosition position, Hex1bWidget content, Hex1bNode? focusRestoreNode = null, Action? onDismiss = null)RemoveStaleAnchoredPopups()
Removes any popup entries whose anchor nodes are stale (have zero bounds). This happens when an anchor node is replaced during reconciliation but the popup still holds a reference to the old node. Call this after layout (Arrange) to clean up stale popups.
Returns: Boolean
True if any stale popups were removed.
public bool RemoveStaleAnchoredPopups()Remarks
PopupStack is designed for cascading menus, dropdowns, and similar UX patterns where:
- Multiple popups can be stacked (e.g., File → Recent Items → filename)
- Each popup layer has its own transparent backdrop
- Clicking a backdrop dismisses that layer (and propagates to layers below)
By default, clicking away from any popup clears the entire stack. To create a "barrier" that stops propagation (e.g., for modal dialogs), use :
e.Popups.Push(() => MyDialog()).AsBarrier();Examples
// Simple popup (full-screen backdrop)
e.Popups.Push(() => BuildDialog());
// Anchored popup (positioned relative to triggering element)
e.Popups.PushAnchored(AnchorPosition.Below, () => BuildMenu());
// Barrier popup (stops cascade dismissal)
e.Popups.Push(() => BuildModal()).AsBarrier();