simvx.core.ui.ui_input¶
UIInputManager: UI input routing, focus, overlay scope, hit-testing.
All UI input flows through one contract: Control._on_gui_input(event).
The mouse events that bubble – a press, a release and the wheel – are offered
to the control under the cursor and then to each of its ancestors until one
claims the event by setting event.handled; all three take that one path
(_bubble).
Mouse motion does not bubble. It reaches the mouse grab while one is held and
otherwise the control under the cursor alone (_handle_mouse_move), so a
widget that tracks the pointer – Slider, ColourPicker – reads motion
through the same _on_gui_input without an ancestor ever seeing it.
Multi-touch (touch_input) is the same: the control hit at finger-down keeps
that finger’s moves and its release.
When a capturing overlay is open (registered via Control.show_overlay),
routing is gated to that overlay’s chain (tree.overlays): a click outside the
chain dismisses it, keyboard events go to the focused descendant with router-level
fallbacks for focus traversal and dismissal. A capture="none" overlay never
scopes input, so the world keeps full input beneath it.
Which key does what is not decided here: the router asks ui/navigation.py
whether a key is bound to ui_focus_next, ui_focus_prev, ui_accept or
ui_cancel, so navigation is rebindable through InputMap like any other
action.
Module Contents¶
Classes¶
Routes UI input events to controls: focus, hover, mouse grab, overlay scope. |
Data¶
API¶
- simvx.core.ui.ui_input.log¶
‘getLogger(…)’
- class simvx.core.ui.ui_input.UIInputManager[source]¶
Routes UI input events to controls: focus, hover, mouse grab, overlay scope.
Initialization
- notify_subtree_removed(control)[source]¶
Release focus / mouse grab when a control (or its subtree) leaves the tree.
Called from
Control._exit_treeso that a destroyed or reparented focused control never lingers as the focus owner and keeps receiving keyboard events. The overlay registry’s own focus-restore path (OverlayLayer.close) handles overlay teardown separately.
- ui_input(root: simvx.core.node.Node | None, mouse_pos=None, button: simvx.core.input.enums.MouseButton | None = None, pressed: bool = True, key: str = '', char: str = '', ctrl: bool | None = None, shift: bool | None = None, alt: bool | None = None, meta: bool | None = None)[source]¶
Route a UI input event.
buttonis aMouseButtonenum for mouse press/release events, orNonefor keyboard / char / pure mouse-move events.ctrl/shift/alt/metaare the modifier state at event time. Leave one unset and it is read from the held-key state (:meth:_modifiers). They reach the control on every event kind, so a widget implements a Shift-click by readingevent.shift.
- touch_input(root: simvx.core.node.Node | None, finger_id: int, action: int, x: float, y: float)[source]¶
Route a multi-touch event.
For controls with
touch_mode='multi', each finger is tracked independently. On down: hit-test for the control, store in_touch_grabs, deliver press. On move: deliver to grabbed control. On up: deliver release, remove grab.
- has_pending_edit() bool[source]¶
True if the focused control holds an uncommitted edit (e.g. a TextEdit).
- commit_pending_edit() None[source]¶
Commit the focused control’s in-progress edit now, if it has one.
Idempotent (no-op when nothing is pending). Consumers call this before tearing down or replacing a focused editor so the typed value is not lost when the widget is removed (e.g. the inspector rebuilding after a rename).