simvx.core.ui.marks¶
One canonical answer to: which visible controls are interactive, and where are they on screen.
A single pure-data pass over a scene tree that returns a :class:ControlMark per visible
- class:
~simvx.core.ui.core.Control, carrying its screen-space rect (fromget_global_rect) and the interaction flags derived from the very predicates the engine uses at runtime:
clickable->mouse_filtertruthy and the rect is non-degenerate (matchesUIInputManager._find_control_at_point: a control receives clicks iff it is visible,mouse_filteris truthy, and the point lands inside its rect).focusable->focus_mode != FocusMode.NONE(matches the focus/tab predicates).
No new member is added to Control: every flag is derived from existing state so there is
exactly one source of truth. This module is backend-agnostic (no renderer, no Vulkan, no
simvx.ai): the two render adapters that consume it are the in-game DebugOverlay (Draw2D)
and the AI set-of-marks pixel overlay.
The tree must be laid out for the current frame before calling this: get_global_rect is
per-frame cached keyed on Control._current_frame (bumped by SceneTree.on_update), so a
pre-layout call returns stale or zero rects.
Module Contents¶
Classes¶
A visible control plus its screen rect and runtime-derived interaction flags. |
Functions¶
Enumerate visible Controls under |
Data¶
API¶
- simvx.core.ui.marks.__all__¶
[‘ControlMark’, ‘enumerate_interactive_controls’]
- class simvx.core.ui.marks.ControlMark[source]¶
A visible control plus its screen rect and runtime-derived interaction flags.
- control: simvx.core.ui.core.Control¶
None
- rect: tuple[float, float, float, float]¶
None
- path: str¶
None
- type_name: str¶
None
- text: str¶
None
- clickable: bool¶
None
- focusable: bool¶
None
- disabled: bool¶
None
- focused: bool¶
None
- mouse_over: bool¶
None
- simvx.core.ui.marks.enumerate_interactive_controls(root: simvx.core.node.Node, *, interactive_only: bool = False) list[simvx.core.ui.marks.ControlMark][source]¶
Enumerate visible Controls under
rootas screen-space :class:ControlMarkrecords.Single DFS pass over
root.walk(include_self=True). A node is included when it is aControlthat is visible in the hierarchy and has a non-degenerate rect; degenerate rects (w <= 0orh <= 0) are skipped silently because that is normal for a 0-sized or anchor/margin-collapsed decorative node (get_rectalready warns only on negative size).With
interactive_only=True, records that are neitherclickablenorfocusableare dropped, leaving only what the mouse and an agent can act on. Note a control isclickablewhenevermouse_filteris truthy (the engine default), so decorative containers drop out only when the author opts them out of hit-testing (mouse_filter = False), exactly matching what the runtime hit-test would route a click to.