simvx.core.ui.graph_editΒΆ

Node graph editor widget for visual programming, animation blend trees, shader graphs.

Provides GraphNode (a draggable node with typed input/output ports) and GraphEdit (a zoomable canvas that manages nodes and connections).

Module ContentsΒΆ

ClassesΒΆ

GraphPort

Input or output port on a GraphNode.

GraphConnection

Connection between two ports on two GraphNodes.

GraphNode

A node in the graph editor with titled header and typed input/output ports.

GraphEdit

Zoomable node graph editor with pan, zoom, and connection management.

DataΒΆ

APIΒΆ

simvx.core.ui.graph_edit.logΒΆ

β€˜getLogger(…)’

simvx.core.ui.graph_edit.__all__ΒΆ

[β€˜GraphPort’, β€˜GraphConnection’, β€˜GraphNode’, β€˜GraphEdit’]

class simvx.core.ui.graph_edit.GraphPort[source]ΒΆ

Input or output port on a GraphNode.

Attributes: name: Display name. type: Type identifier for connection validation. colour: RGBA colour for the port indicator.

name: strΒΆ

None

type: strΒΆ

β€˜default’

colour: tuple[float, float, float, float]ΒΆ

(0.8, 0.8, 0.8, 1.0)

class simvx.core.ui.graph_edit.GraphConnection[source]ΒΆ

Connection between two ports on two GraphNodes.

Attributes: from_node: Source node name. from_port: Source output port index. to_node: Destination node name. to_port: Destination input port index.

from_node: strΒΆ

None

from_port: intΒΆ

None

to_node: strΒΆ

None

to_port: intΒΆ

None

class simvx.core.ui.graph_edit.GraphNode(**kwargs)[source]ΒΆ

Bases: simvx.core.ui.containers.Container

A node in the graph editor with titled header and typed input/output ports.

Example: node = GraphNode(title=”Add”) node.add_input(β€œA”, type=”float”) node.add_input(β€œB”, type=”float”) node.add_output(β€œResult”, type=”float”) graph.add_graph_node(node)

Initialization

titleΒΆ

β€˜Property(…)’

graph_positionΒΆ

β€˜Property(…)’

size_xΒΆ

β€˜Property(…)’

size_yΒΆ

β€˜Property(…)’

__transient__ΒΆ

β€˜frozenset(…)’

add_input(name: str, type: str = 'default') → int[source]ΒΆ

Add an input port. Returns port index.

add_output(name: str, type: str = 'default') → int[source]ΒΆ

Add an output port. Returns port index.

get_input_port_position(index: int) → tuple[float, float][source]ΒΆ

Position of input port in local node space.

get_output_port_position(index: int) → tuple[float, float][source]ΒΆ

Position of output port in local node space.

separationΒΆ

β€˜Property(…)’

on_enter_tree()ΒΆ
on_ready()ΒΆ
on_exit_tree()ΒΆ
add_child(node: simvx.core.node.T) → simvx.core.node.TΒΆ
remove_child(node: simvx.core.node.Node) → NoneΒΆ
mark_layout_dirty()ΒΆ
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(…)’

anchorΒΆ

β€˜Property(…)’

insetΒΆ

β€˜Property(…)’

dismiss_on_outside_clickΒΆ

β€˜Property(…)’

clip_contentsΒΆ

β€˜Property(…)’

focus_modeΒΆ

β€˜Property(…)’

tooltipΒΆ

β€˜Property(…)’

pointer_filterΒΆ

β€˜Property(…)’

cursor_shapeΒΆ

β€˜Property(…)’

pointer_types: frozenset[simvx.core.input.enums.PointerType] | NoneΒΆ

None

touch_target: boolΒΆ

False

property wants_text_input: boolΒΆ
size_flags_horizontalΒΆ

β€˜Property(…)’

size_flags_verticalΒΆ

β€˜Property(…)’

stretch_ratioΒΆ

β€˜Property(…)’

max_sizeΒΆ

β€˜Property(…)’

property size: simvx.core.math.types.Vec2ΒΆ
property min_size: simvx.core.math.types.Vec2ΒΆ
content_signature() → objectΒΆ
content_uses(chars: str) → boolΒΆ
autosize_to_content() → NoneΒΆ
accepts_pointersΒΆ

β€˜Property(…)’

property theme: simvx.core.ui.types.Theme | NoneΒΆ
property mouse_over: boolΒΆ
property disabled: boolΒΆ
get_theme() → simvx.core.ui.types.ThemeΒΆ
property viewport_size: simvx.core.math.types.Vec2ΒΆ
property viewport_insets: tuple[float, float, float, float]ΒΆ
queue_redraw()ΒΆ
size_floor() → tuple[float, float]ΒΆ
get_minimum_size() → simvx.core.math.types.Vec2ΒΆ
get_rect() → tuple[float, float, float, float]ΒΆ
get_global_rect() → tuple[float, float, float, float]ΒΆ
property focus_rect: tuple[float, float, float, float] | NoneΒΆ
is_point_inside(point) → boolΒΆ
is_hit(event: simvx.core.input.events.PointerEvent) → boolΒΆ
classmethod __init_subclass__(**kwargs)ΒΆ
activate() → boolΒΆ
focus_next_control()ΒΆ
focus_previous_control()ΒΆ
set_drag_preview(control: simvx.core.ui.core.Control)ΒΆ
property is_overlay_open: boolΒΆ
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ΒΆ
close_overlay() → NoneΒΆ
positionΒΆ

β€˜_SpatialVecProperty(…)’

rotationΒΆ

β€˜Property(…)’

scaleΒΆ

β€˜_SpatialVecProperty(…)’

top_levelΒΆ

β€˜Property(…)’

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)ΒΆ
to_global(point) → simvx.core.math.types.Vec2ΒΆ
to_local(point) → simvx.core.math.types.Vec2ΒΆ
transform_points(points: list[simvx.core.math.types.Vec2]) → list[simvx.core.math.types.Vec2]ΒΆ
wrap_screen(margin: float = 20)ΒΆ
post_processedΒΆ

β€˜Property(…)’

property transform_render_dirty: boolΒΆ
strict_errors: ClassVar[bool]ΒΆ

True

dev_checks: ClassVar[bool]ΒΆ

None

dev_warnings: ClassVar[bool]ΒΆ

None

freeze_check_interval: ClassVar[float]ΒΆ

1.0

dynamic: boolΒΆ

False

visibleΒΆ

β€˜Property(…)’

update_modeΒΆ

β€˜Property(…)’

drag_thresholdΒΆ

β€˜Property(…)’

focus_enteredΒΆ

β€˜Signal(…)’

focus_exitedΒΆ

β€˜Signal(…)’

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

None

property name: strΒΆ
property visible_in_tree: boolΒΆ
property input_player: simvx.core.input.players.InputPlayerΒΆ
property input_context: simvx.core.input.contexts.InputContext | NoneΒΆ
reset_error() → 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_update(dt: float) → NoneΒΆ
on_fixed_update(dt: float) → NoneΒΆ
on_draw(canvas) → NoneΒΆ
on_draw_3d(gizmos) → NoneΒΆ
on_picked(event: simvx.core.input.events.PickEvent) → bool | NoneΒΆ
on_gui_input(event: simvx.core.input.events.GuiInputEvent) → bool | NoneΒΆ
start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandleΒΆ
stop_coroutine(gen_or_handle)ΒΆ
property focused: boolΒΆ
drag_threshold_for(pointer_type: simvx.core.input.enums.PointerType | str) → floatΒΆ
grab_focus() → NoneΒΆ
release_focus() → NoneΒΆ
capture_pointer(pointer_id: int | None = None) → NoneΒΆ
release_pointer(pointer_id: int | None = None) → NoneΒΆ
property render_dirty: boolΒΆ
clear_children()ΒΆ
destroy()ΒΆ
property destroying: boolΒΆ
property destroyed: 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__()ΒΆ
class simvx.core.ui.graph_edit.GraphEdit(**kwargs)[source]ΒΆ

Bases: simvx.core.ui.core.Control

Zoomable node graph editor with pan, zoom, and connection management.

Nodes are placed in graph space. The viewport applies zoom and scroll offset to determine which portion of the graph is visible.

Example: graph = GraphEdit() node_a = GraphNode(name=”A”, title=”Source”) node_a.add_output(β€œOut”) graph.add_graph_node(node_a)

node_b = GraphNode(name="B", title="Sink")
node_b.add_input("In")
graph.add_graph_node(node_b)

graph.connect_node("A", 0, "B", 0)

Initialization

pointer_filterΒΆ

β€˜Property(…)’

size_xΒΆ

β€˜Property(…)’

size_yΒΆ

β€˜Property(…)’

add_graph_node(node: simvx.core.ui.graph_edit.GraphNode)[source]ΒΆ

Register a GraphNode in this editor.

remove_graph_node(name: str)[source]ΒΆ

Remove a GraphNode and all its connections.

graph_node(name: str) → simvx.core.ui.graph_edit.GraphNode | None[source]ΒΆ

Retrieve a registered GraphNode by name, or None.

Named for its siblings add_graph_node / remove_graph_node rather than for :meth:~simvx.core.node.Node.node_at, which it would otherwise shadow: this reads one widget’s own registry, not the scene tree, and a GraphEdit must still be able to resolve a node path like any other Control.

connect_node(from_node: str, from_port: int, to_node: str, to_port: int)[source]ΒΆ

Create a connection between two ports.

disconnect_node(from_node: str, from_port: int, to_node: str, to_port: int)[source]ΒΆ

Remove a specific connection.

get_connections() → list[simvx.core.ui.graph_edit.GraphConnection][source]ΒΆ

Return a copy of the current connections list.

clear_connections()[source]ΒΆ

Remove all connections.

set_zoom(zoom: float)[source]ΒΆ

Set zoom level, clamped to [0.25, 2.0].

property zoom: float[source]ΒΆ
property scroll_offset: tuple[float, float][source]ΒΆ
center_on_node(name: str)[source]ΒΆ

Pan the viewport to center on the named node.

on_gui_input(event)[source]ΒΆ
on_draw(renderer)[source]ΒΆ
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(…)’

anchorΒΆ

β€˜Property(…)’

insetΒΆ

β€˜Property(…)’

dismiss_on_outside_clickΒΆ

β€˜Property(…)’

clip_contentsΒΆ

β€˜Property(…)’

focus_modeΒΆ

β€˜Property(…)’

tooltipΒΆ

β€˜Property(…)’

cursor_shapeΒΆ

β€˜Property(…)’

pointer_types: frozenset[simvx.core.input.enums.PointerType] | NoneΒΆ

None

touch_target: boolΒΆ

False

property wants_text_input: boolΒΆ
size_flags_horizontalΒΆ

β€˜Property(…)’

size_flags_verticalΒΆ

β€˜Property(…)’

stretch_ratioΒΆ

β€˜Property(…)’

max_sizeΒΆ

β€˜Property(…)’

property size: simvx.core.math.types.Vec2ΒΆ
property min_size: simvx.core.math.types.Vec2ΒΆ
content_signature() → objectΒΆ
content_uses(chars: str) → boolΒΆ
autosize_to_content() → NoneΒΆ
accepts_pointersΒΆ

β€˜Property(…)’

property theme: simvx.core.ui.types.Theme | NoneΒΆ
property mouse_over: boolΒΆ
property disabled: boolΒΆ
get_theme() → simvx.core.ui.types.ThemeΒΆ
property viewport_size: simvx.core.math.types.Vec2ΒΆ
property viewport_insets: tuple[float, float, float, float]ΒΆ
queue_redraw()ΒΆ
size_floor() → tuple[float, float]ΒΆ
get_minimum_size() → simvx.core.math.types.Vec2ΒΆ
add_child(node: simvx.core.node.T) → simvx.core.node.TΒΆ
get_rect() → tuple[float, float, float, float]ΒΆ
get_global_rect() → tuple[float, float, float, float]ΒΆ
property focus_rect: tuple[float, float, float, float] | NoneΒΆ
is_point_inside(point) → boolΒΆ
is_hit(event: simvx.core.input.events.PointerEvent) → boolΒΆ
classmethod __init_subclass__(**kwargs)ΒΆ
activate() → boolΒΆ
focus_next_control()ΒΆ
focus_previous_control()ΒΆ
set_drag_preview(control: simvx.core.ui.core.Control)ΒΆ
property is_overlay_open: boolΒΆ
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ΒΆ
close_overlay() → NoneΒΆ
positionΒΆ

β€˜_SpatialVecProperty(…)’

rotationΒΆ

β€˜Property(…)’

scaleΒΆ

β€˜_SpatialVecProperty(…)’

top_levelΒΆ

β€˜Property(…)’

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)ΒΆ
to_global(point) → simvx.core.math.types.Vec2ΒΆ
to_local(point) → simvx.core.math.types.Vec2ΒΆ
transform_points(points: list[simvx.core.math.types.Vec2]) → list[simvx.core.math.types.Vec2]ΒΆ
wrap_screen(margin: float = 20)ΒΆ
post_processedΒΆ

β€˜Property(…)’

property transform_render_dirty: boolΒΆ
strict_errors: ClassVar[bool]ΒΆ

True

dev_checks: ClassVar[bool]ΒΆ

None

dev_warnings: ClassVar[bool]ΒΆ

None

freeze_check_interval: ClassVar[float]ΒΆ

1.0

dynamic: boolΒΆ

False

visibleΒΆ

β€˜Property(…)’

update_modeΒΆ

β€˜Property(…)’

drag_thresholdΒΆ

β€˜Property(…)’

focus_enteredΒΆ

β€˜Signal(…)’

focus_exitedΒΆ

β€˜Signal(…)’

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

None

property name: strΒΆ
property visible_in_tree: boolΒΆ
property input_player: simvx.core.input.players.InputPlayerΒΆ
property input_context: simvx.core.input.contexts.InputContext | NoneΒΆ
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_3d(gizmos) → NoneΒΆ
on_picked(event: simvx.core.input.events.PickEvent) → bool | NoneΒΆ
start_coroutine(gen: simvx.core.descriptors.Coroutine) → simvx.core.descriptors.CoroutineHandleΒΆ
stop_coroutine(gen_or_handle)ΒΆ
property focused: boolΒΆ
drag_threshold_for(pointer_type: simvx.core.input.enums.PointerType | str) → floatΒΆ
grab_focus() → NoneΒΆ
release_focus() → NoneΒΆ
capture_pointer(pointer_id: int | None = None) → NoneΒΆ
release_pointer(pointer_id: int | None = None) → NoneΒΆ
property render_dirty: boolΒΆ
clear_children()ΒΆ
destroy()ΒΆ
property destroying: boolΒΆ
property destroyed: 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__()ΒΆ