simvx.core.ui.overlay

The tree-owned overlay layer: an ordered registry of on-top UI overlays.

One :class:OverlayLayer per :class:SceneTree (tree.overlays) is the single source of truth for “what is on top, in what order, and what it captures”. It replaces the wrong render-iff-self-is-on-the-modal-stack coupling: layering is registry insertion order, input scope is derived from the topmost capturing entry, and background inertness is derived from any inert entry.

This module lives in core and never imports simvx.graphics at module level. The single collector :func:iter_overlay_draws is consumed identically by both the immediate :meth:SceneTree.render path and the retained item pipeline, so desktop == web and headless == live hold by construction.

Module Contents

Classes

OverlayEntry

One registered overlay (design §3). Frozen: the registry holds entries by value.

OverlayLayer

An ordered registry of open overlays owned by one :class:SceneTree.

Functions

iter_overlay_draws

Yield (kind, control, entry) overlay draws for viewport in open order.

Data

API

simvx.core.ui.overlay.__all__

[‘OverlayEntry’, ‘OverlayLayer’, ‘iter_overlay_draws’, ‘DEFAULT_SCRIM_COLOUR’]

simvx.core.ui.overlay.DEFAULT_SCRIM_COLOUR: tuple[float, float, float, float]

(0.0, 0.0, 0.0, 0.5)

class simvx.core.ui.overlay.OverlayEntry[source]

One registered overlay (design §3). Frozen: the registry holds entries by value.

modality is the preset string; the derived per-entry booleans are capture_input / dim / inert / dismiss_on_outside_click. owner is the logical chain owner (the MenuBar for a dropdown/submenu chain, else the control itself) and drives whole-chain dismissal. viewport is the owning render target (None = the main viewport). dim_colour is resolved from the theme at :meth:OverlayLayer.open so the collector needs no theme lookup. prev_focus is the focus snapshot restored on close. Draw and input order are the registry’s list (insertion) order, so there is no seq field.

control: Any

None

modality: str

None

capture_input: bool

None

dim: bool

None

inert: bool

None

dismiss_on_outside_click: bool

None

dim_colour: tuple[float, float, float, float]

None

owner: Any

None

viewport: Any

None

prev_focus: Any

None

static expand_preset(modality: str, *, dim: bool | None = None, dismiss: bool | None = None, inert: bool | None = None) tuple[bool, bool, bool, bool][source]

Resolve modality to (capture_input, dim, dismiss, inert).

dim / dismiss / inert (None = take the preset default) override individual flags. capture_input is preset-only.

class simvx.core.ui.overlay.OverlayLayer(tree: Any)[source]

An ordered registry of open overlays owned by one :class:SceneTree.

Insertion order == draw order == open-chain order. Empty registry is an O(1) truthiness check (the zero-cost gate on every hot path).

Initialization

__slots__

(‘_tree’, ‘_entries’)

__bool__() bool[source]
__len__() int[source]
open(control: Any, entry: simvx.core.ui.overlay.OverlayEntry) None[source]

Register entry for control on top of the stack.

Snapshots prior focus and focuses the first focusable descendant when the entry is capturing. Bumps tree._structure_version (a registry mutation is a structural change) and emits tree.overlay_opened.

close(control: Any) None[source]

Pop control and every entry above it sharing its owner (the chain).

control is ALWAYS popped; entries above it that share its owner are popped too (whole-chain dismissal), while interleaved entries of OTHER owners (e.g. a none tooltip sitting between a dropdown and its submenu) are left in place. Restores prev_focus per popped entry (LIFO, top-down) iff the prior-focus control is still in this tree, else clears focus. Bumps tree._structure_version and emits tree.overlay_closed per popped control. Idempotent.

chain_base(owner: Any) Any | None[source]

Return the lowest (earliest-opened) overlay control whose owner is owner.

Closing the base pops the whole owner chain (LIFO), so this is the handle for whole-chain dismissal (an outside click / Escape on a menu chain closes the bar + popup + submenu in one action).

close_all() None[source]

Pop every open overlay (used on scene change / teardown).

draw_set() tuple[Any, ...][source]

Return every open overlay control in insertion order.

topmost_capturing() Any | None[source]

Return the topmost capturing overlay control, skipping capture=none.

any_inert() bool[source]

True if any open overlay is inert (drives tree pause). Short-circuits empty.

entry_of(control: Any) simvx.core.ui.overlay.OverlayEntry | None[source]

Return the open entry for control, or None.

scope_root_of(control: Any) Any[source]

Return the chain owner for control (chain-aware input scope).

simvx.core.ui.overlay.iter_overlay_draws(tree: Any, *, viewport: Any = None) collections.abc.Iterator[tuple[str, Any, simvx.core.ui.overlay.OverlayEntry]][source]

Yield (kind, control, entry) overlay draws for viewport in open order.

kind is "dim" (a full-screen scrim drawn behind the overlay) then "overlay" (the overlay control’s subtree). Filtered to entries whose entry.viewport is viewport (None = the main viewport). The generator is only entered inside an if tree.overlays guard, so it is allocation-free and O(1) when unused.