simvx.core.ui.core

Core UI types: Control, Theme, Colour, UIInputEvent, FocusMode, AnchorPreset, SizeFlags, DragData.

Module Contents

Classes

Control

Base class for all UI elements.

Data

API

simvx.core.ui.core.log

‘getLogger(…)’

simvx.core.ui.core.__all__

[‘Control’, ‘Theme’, ‘ThemeColour’, ‘ThemeSize’, ‘ThemeStyleBox’, ‘Colour’, ‘UIInputEvent’, ‘FocusMo…

class simvx.core.ui.core.Control(**kwargs)[source]

Bases: simvx.core.nodes_2d.node2d.Node2D

Base class for all UI elements.

Supports anchors, margins, sizing, focus, drag-and-drop, and input handling. Widgets draw themselves using the renderer passed to draw().

Example: control = Control(name=”panel”) control.size = Vec2(200, 100) control.set_anchor_preset(AnchorPreset.FULL_RECT)

Initialization

size_x

‘Property(…)’

size_y

‘Property(…)’

min_size_x

‘Property(…)’

min_size_y

‘Property(…)’

anchor_left

‘Property(…)’

anchor_top

‘Property(…)’

anchor_right

‘Property(…)’

anchor_bottom

‘Property(…)’

margin_left

‘Property(…)’

margin_top

‘Property(…)’

margin_right

‘Property(…)’

margin_bottom

‘Property(…)’

dismiss_on_outside_click

‘Property(…)’

clip_contents

‘Property(…)’

focus_mode

‘Property(…)’

tooltip

‘Property(…)’

mouse_filter

‘Property(…)’

size_flags_horizontal

‘Property(…)’

size_flags_vertical

‘Property(…)’

stretch_ratio

‘Property(…)’

max_size

‘Property(…)’

property size: simvx.core.math.types.Vec2[source]

Size backed by size_x/size_y Properties (inspector-synced).

property min_size: simvx.core.math.types.Vec2[source]

Minimum size, backed by min_size_x/min_size_y Properties (inspector-synced).

A view, like :attr:size: assign a whole vector to change it. Editing the returned vector in place changes nothing.

content_signature() object[source]

What :meth:get_minimum_size measures, beyond the font metrics.

Assigning new content to a control does not resize it; that is the caller’s to do. A re-fit therefore has to distinguish content it may re-measure from content that has changed underneath it since, because re-measuring the latter would apply a resize nobody asked for, at whatever moment the metrics happened to move. Subclasses whose minimum size depends on their own state return it here.

The default says “nothing that can change”, which is the safe answer: it makes every re-fit re-measure, as it would without this at all.

content_uses(chars: str) bool[source]

Whether new metrics for chars can change this control’s minimum size.

A control answering False is left alone when only those characters moved, which is what keeps a browser rasterising glyphs a few at a time from re-fitting an entire UI on every frame it does so. Subclasses that size themselves to a known string answer from it.

The default says any character might matter, which is the safe answer.

autosize_to_content() None[source]

Size this control to fit its content, and keep it fitted.

How wide a string is depends on the font it is drawn with, and a renderer can resolve that font after the scene has been built. Controls sized this way are measured again when that happens, so a button never ends up narrower than the label inside it.

A size set from anywhere else wins: a container that lays this control out, or a game that assigns size, keeps its size, and only the layout is told to run again.

touch_mode: str

‘mouse’

property theme: simvx.core.ui.types.Theme | None[source]
property mouse_over: bool[source]
property focused: bool[source]
property disabled: bool[source]
get_theme() simvx.core.ui.types.Theme[source]

Get effective theme (own -> parent -> default).

queue_redraw()[source]

Mark this control as needing a redraw. Propagates upward to parent.

Extends :meth:Drawable2D.queue_redraw additively: it sets the item-pipeline render-dirty bit (read by the item RenderItemCache) AND keeps the _draw_dirty/_DrawRecorder cache path (read by the Draw2D _draw_recursive walk the editor play-mode game viewport + web runtime still use).

get_minimum_size() simvx.core.math.types.Vec2[source]

Minimum size needed to display content. Subclasses override.

add_child(node: simvx.core.node.T) simvx.core.node.T[source]

Add a child, and forget the measurements it just changed (see :meth:Node.add_child).

get_rect() tuple[float, float, float, float][source]

Get (x, y, width, height) in parent space.

get_global_rect() tuple[float, float, float, float][source]

Get (x, y, width, height) in screen space.

The origin is :attr:world_position: the anchor/margin rect is part of the 2D transform chain (:meth:_layout_offset), so there is one walk up the tree and not two, and a control’s drawn position and its reported position cannot disagree.

The extent still comes from :meth:get_rect, which is why _rect_frame stays a field of its own rather than merging into the transform epoch: the two are stamped at different moments, and one field would let a fresh transform certify a stale (width, height).

Cached per layout frame, and auto-expires when the epoch advances.

One class diverges on purpose. While registered as an overlay, SplashScreen and AttributionWatermark (_FullscreenOverlay) override both this and :meth:get_rect to cover the whole render target wherever they are parented, so for them this does NOT equal world_position. The overlay collector draws them from their rect and never reads their world position.

is_point_inside(point) bool[source]

Check if point (screen coords) is inside this control.

place_bottom_strip(height: float) None[source]

Anchor this control as a full-width horizontal strip at the bottom.

Equivalent to set_anchor_preset(AnchorPreset.BOTTOM_WIDE) plus margin_top = -height. The negative-margin convention is correct but surprising; this shortcut makes intent obvious.

place_top_strip(height: float) None[source]

Anchor this control as a full-width horizontal strip at the top.

set_anchor_preset(preset: simvx.core.ui.enums.AnchorPreset)[source]

Set anchors from a preset.

Example: panel.set_anchor_preset(AnchorPreset.FULL_RECT) # fills parent label.set_anchor_preset(AnchorPreset.CENTER) # centered

activate() bool[source]

Act on this control as a completed click would; return whether it acted.

This is what the ui_accept key (Enter by default) does to the focus owner. The router calls it only after the focused widget has declined the key, so a widget that wants Enter for itself keeps it by setting event.handled – a text field submits, a code editor inserts a newline, and neither is activated.

A plain Control has no activation semantics and returns False. Button fires pressed, CheckBox toggles and RadioButton selects, which is what Godot’s ui_accept and Unity’s ISubmitHandler do for the same widgets. Everything else is deliberately inert.

It is public so activation is one call rather than a synthesised event: button.activate() is exactly what the keyboard does.

The call itself is unconditional: it does not consult disabled or visible, because the caller is the policy. Both engine paths into it apply their own – a click never reaches a disabled control, and the router activates only a focusable owner – so an application calling this directly is saying “do it now”, the way emitting pressed would.

set_focus()[source]

Request focus for this control.

grab_focus()[source]

Claim keyboard focus for this control.

Unfocuses the currently focused control (if any) and sets focus to this one. Respects focus_mode: NONE-mode controls cannot receive focus.

release_focus()[source]

Release focus from this control.

has_focus() bool[source]

Return True if this control currently has keyboard focus.

focus_next_control()[source]

Move focus to the next control in tab order.

An explicit focus_next link wins; otherwise the tab order is walked from this control’s position in the tree, wrapping at the end. Hidden and disabled controls are skipped. When this control sits inside an open capturing overlay the walk is confined to that overlay; a control outside one is unaffected by it.

focus_previous_control()[source]

Move focus to the previous control in tab order (see :meth:focus_next_control).

grab_mouse()[source]

Capture mouse – all mouse events route to this control until released.

release_mouse()[source]

Release mouse capture.

set_drag_preview(control: simvx.core.ui.core.Control)[source]

Set a visual preview control for the current drag operation.

property is_overlay_open: bool[source]

True while this control is registered as an open overlay.

show_overlay(modality: str = 'light', *, dim: bool | None = None, dismiss: bool | None = None, inert: bool | None = None, owner: simvx.core.ui.core.Control | None = None, initial_focus: simvx.core.ui.core.Control | None = None) None[source]

Register this control as an on-top overlay until :meth:close_overlay.

modality is one of "none" / "light" / "blocking" (a preset bundle of the flags below). dim / dismiss / inert (None = preset default) override individual flags. owner is the logical chain owner for whole-chain dismissal + input scope (e.g. a MenuBar for its dropdown + submenu overlays); defaults to self. initial_focus is the descendant to focus when the overlay is capturing (None = the first focusable descendant). Positioning is the widget’s own job: position first, then call show_overlay to register.

close_overlay() None[source]

Pop this control (and its open chain) from the overlay registry. Idempotent.

Mirrors :meth:show_overlay, which sets visible = True: closing hides the control again so a persistent (non-freed) overlay – a reused title/menu screen – stops drawing over the scene once dismissed. A consumer that frees its overlay on close is unaffected (the hide is harmless); one that reuses it gets visible = True back on the next show_overlay.

position

‘_SpatialVecProperty(…)’

rotation

‘Property(…)’

scale

‘_SpatialVecProperty(…)’

z_index

‘Property(…)’

z_as_relative

‘Property(…)’

render_layer

‘Property(…)’

set_render_layer(index: int, enabled: bool = True) None
is_on_render_layer(index: int) bool
property absolute_z_index: int
property rotation_degrees: float
property world_position: simvx.core.math.types.Vec2
property world_rotation: float
property world_scale: simvx.core.math.types.Vec2
property world_transform: tuple[simvx.core.math.types.Vec2, simvx.core.math.types.Vec2, float]
property forward: simvx.core.math.types.Vec2
property right: simvx.core.math.types.Vec2
translate(offset: tuple[float, float] | numpy.ndarray)
rotate(radians: float)
rotate_deg(degrees: float)
look_at(target: tuple[float, float] | numpy.ndarray)
transform_points(points: list[simvx.core.math.types.Vec2]) list[simvx.core.math.types.Vec2]
draw_polygon(renderer, points: list[simvx.core.math.types.Vec2], closed=True, colour=None)
wrap_screen(margin: float = 20)
hdr

‘Property(…)’

property transform_render_dirty: bool
strict_errors: ClassVar[bool]

True

dev_checks: ClassVar[bool]

None

script_error_raised

‘Signal(…)’

dynamic: bool

False

visible

‘Property(…)’

update_mode

‘Property(…)’

__properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]

None

classmethod __init_subclass__(**kwargs)
property name: str
property visible_in_tree: bool
reset_error() None
remove_child(node: simvx.core.node.Node) None
reparent(new_parent: simvx.core.node.Node)
node_at(path, default=_NO_DEFAULT)
find(target, *, direct: bool = False)
find_all(target, *, direct: bool = False)
expect(target, *, direct: bool = False)
ancestor(target)
walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]
property path: str
property is_scene_root: bool
add_to_group(group: str)
remove_from_group(group: str)
is_in_group(group: str) bool
on_ready() None
on_enter_tree() None
on_exit_tree() None
on_update(dt: float) None
on_fixed_update(dt: float) None
on_draw(renderer) None
on_picked(event: simvx.core.events.InputEvent) None
on_unhandled_input(event: simvx.core.events.TreeInputEvent) None
start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle
stop_coroutine(gen_or_handle)
property render_dirty: bool
clear_children()
destroy()
property destroying: bool
call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None
property app
property tree: simvx.core.scene_tree.SceneTree
property physics
property physics_2d
__getitem__(key: str)
classmethod get_properties() dict[str, simvx.core.descriptors.Property]
__repr__()