simvx.editor.workspace_tabs¶
Workspace Tabs — Unified tab bar for scene and script tabs.
Data model and manager for the VS Code-style unified tab bar where scene tabs and script tabs coexist. Multiple scenes can be open simultaneously, each with its own undo/selection/camera state.
Module Contents¶
Classes¶
Per-scene snapshot holding all scene-specific state. |
|
Per-script tab state. |
|
Editor-only scratch buffer — VS Code “Untitled-N” pattern. |
|
Unified tab manager for scene and script tabs. |
|
Modal confirmation dialog shown when closing a tab with unsaved changes. |
|
Modal overlay for choosing a new scene root type. |
Data¶
API¶
- simvx.editor.workspace_tabs.log¶
‘getLogger(…)’
- class simvx.editor.workspace_tabs.SceneTabState[source]¶
Per-scene snapshot holding all scene-specific state.
- scene_tree: simvx.core.SceneTree¶
None
- scene_path: pathlib.Path | None¶
None
- selection: simvx.core.Selection¶
‘field(…)’
- undo_stack: simvx.core.UndoStack¶
‘field(…)’
- editor_camera: simvx.core.OrbitCamera3D¶
‘field(…)’
- viewport_sub_mode: str¶
‘3d’
- modified: bool¶
False
- saved_scene_data: dict | None¶
None
- playing_root: simvx.core.Node | None¶
None
- placeholder: simvx.core.Control¶
‘field(…)’
- tab_name: str¶
‘Untitled’
- source_file: str | None¶
None
- source_module: Any¶
None
- file_classification: str = <Multiline-String>¶
- identity_hints: dict¶
‘field(…)’
- property tab_widget: simvx.core.Control[source]¶
The widget representing this tab in a TabContainer.
- classmethod create(root_type: type = Node, name: str = 'Root') simvx.editor.workspace_tabs.SceneTabState[source]¶
Create a fresh scene tab with sensible defaults.
- class simvx.editor.workspace_tabs.ScriptTabState[source]¶
Per-script tab state.
- key: str¶
None
- kind: str¶
None
- node: simvx.core.Node | None¶
None
- editor: simvx.core.CodeTextEdit¶
None
- saved_text: str¶
None
- tab_name: str¶
None
- class simvx.editor.workspace_tabs.UntitledTabState[source]¶
Editor-only scratch buffer — VS Code “Untitled-N” pattern.
Holds a Python source buffer that has not yet been saved to disk. The buffer lives purely in editor memory (this dataclass + a CodeTextEdit widget); it is never serialised onto a Node attribute or any scene file. On save (Ctrl+S) the editor prompts for a destination path; once written the tab is replaced with a regular file-backed
ScriptTabState.ordinalis the auto-assigned 1-based sequence number that produced the default tab nameUntitled-N.py. The :class:WorkspaceTabskeeps track of the next ordinal so closing and reopening Untitled tabs reuses the lowest available number.- ordinal: int¶
None
- editor: simvx.core.CodeTextEdit¶
None
- tab_name: str¶
None
- property tab_widget: simvx.core.Control[source]¶
The widget representing this tab in a TabContainer.
- property is_dirty: bool[source]¶
Untitled buffers are dirty as soon as the user types anything.
An empty Untitled buffer is treated as clean — closing it without any input should not prompt to save.
- save() None[source]¶
No-op — actual save routes through the editor’s Save-As file dialog.
Implemented for tab-protocol parity (e.g.
WorkspaceTabs.save_all_scriptsiterating all tabs). The promotion to aScriptTabStatehappens in- Meth:
WorkspaceTabs.promote_untitled_to_fileafter the user picks a destination path.
- class simvx.editor.workspace_tabs.WorkspaceTabs[source]¶
Unified tab manager for scene and script tabs.
Initialization
- MODIFIED_TEXT_COLOUR¶
(0.95, 0.78, 0.35, 1.0)
- MODIFIED_PREFIX¶
‘● ‘
- add_scene_tab(state: simvx.editor.workspace_tabs.SceneTabState) int[source]¶
Add a scene tab and return its index.
- property active_scene: simvx.editor.workspace_tabs.SceneTabState | None[source]¶
The active scene tab state, or None if a script tab is active.
- open_script(node: simvx.core.Node, project_path_fn=None, line: int | None = None) int[source]¶
Open or switch to a script tab for the given node.
When
lineis given (1-indexed), position the cursor at that line after opening/switching. Used for error navigation.
- open_file(path, line: int | None = None) int[source]¶
Open or switch to a script tab backed by a file path.
Useful for error navigation from the console: the traceback identifies a file path on disk, which may or may not be attached to a node. If a tab already exists for this path, switch to it; otherwise open a new file-backed script tab.
- property current_editor: simvx.core.CodeTextEdit | None[source]¶
The active script or Untitled tab’s editor, if any.
- untitled_tabs() list[simvx.editor.workspace_tabs.UntitledTabState][source]¶
All currently-open Untitled scratch buffers (in tab order).
- new_untitled() int[source]¶
Open a fresh empty Untitled scratch buffer; return its tab index.
The buffer lives purely in editor state. Promotion to a real file-backed tab happens via :meth:
promote_untitled_to_fileafter the user invokes Save and picks a path through the file dialog.
- promote_untitled_to_file(index: int, path: pathlib.Path | str) bool[source]¶
Convert an Untitled tab at index into a file-backed script tab.
Writes the current editor text to path, then replaces the
- Class:
UntitledTabStateslot with a fresh :class:ScriptTabStatekeyed off the resolved file path. The sameCodeTextEditwidget is reused so the tab container does not need to be rebuilt.
Returns
Trueon success,Falseif the path could not be written (the Untitled tab is left untouched in that case).
- class simvx.editor.workspace_tabs.UnsavedChangesDialog(**kwargs)[source]¶
Bases:
simvx.core.PanelModal confirmation dialog shown when closing a tab with unsaved changes.
Initialization
- DIALOG_WIDTH¶
300.0
- DIALOG_HEIGHT¶
160.0
- BUTTON_HEIGHT¶
32.0
- BUTTON_GAP¶
8.0
- show_dialog(tab_name: str = '', parent_size: simvx.core.Vec2 | None = None)[source]¶
Show the dialog with the given tab name in the message.
- style¶
‘ThemeStyleBox(…)’
- property bg_colour¶
- property border_colour¶
- property border_width¶
- get_minimum_size() simvx.core.math.types.Vec2¶
- draw(renderer)¶
- size_x¶
‘Property(…)’
- 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(…)’
- property size: simvx.core.math.types.Vec2¶
- touch_mode: str¶
‘mouse’
- property theme: simvx.core.ui.types.Theme | None¶
- property mouse_over: bool¶
- property focused: bool¶
- property disabled: bool¶
- get_theme() simvx.core.ui.types.Theme¶
- queue_redraw()¶
- get_rect() tuple[float, float, float, float]¶
- get_global_rect() tuple[float, float, float, float]¶
- is_point_inside(point) bool¶
- set_anchor_preset(preset: simvx.core.ui.enums.AnchorPreset)¶
- set_focus()¶
- grab_focus()¶
- release_focus()¶
- has_focus() bool¶
- focus_next_control()¶
- focus_previous_control()¶
- grab_mouse()¶
- release_mouse()¶
- set_drag_preview(control: simvx.core.ui.core.Control)¶
- draw_popup(renderer)¶
- is_popup_point_inside(point) bool¶
- popup_input(event)¶
- dismiss_popup()¶
- 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 position: simvx.core.math.types.Vec2¶
- property rotation: float¶
- property rotation_degrees: float¶
- property scale: simvx.core.math.types.Vec2¶
- property world_position: simvx.core.math.types.Vec2¶
- property world_rotation: float¶
- property world_scale: simvx.core.math.types.Vec2¶
- 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)¶
- strict_errors: ClassVar[bool]¶
True
- script_error_raised¶
‘Signal(…)’
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property process_mode: simvx.core.descriptors.ProcessMode¶
- property visible: bool¶
- reset_error() None¶
- add_child(node: simvx.core.node.Node) simvx.core.node.Node¶
- remove_child(node: simvx.core.node.Node)¶
- reparent(new_parent: simvx.core.node.Node)¶
- get_node(path: str) simvx.core.node.Node¶
- find_child(name: str, recursive: bool = False) simvx.core.node.Node | None¶
- find(node_type: type, recursive: bool = True) simvx.core.node.Node | None¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- ready() None¶
- enter_tree() None¶
- exit_tree() None¶
- process(dt: float) None¶
- physics_process(dt: float) None¶
- picked(event: simvx.core.events.InputEvent) None¶
- handle_input(event: simvx.core.events.TreeInputEvent) None¶
- unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- clear_children()¶
- destroy()¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶
- class simvx.editor.workspace_tabs.NewSceneDialog(**kwargs)[source]¶
Bases:
simvx.core.PanelModal overlay for choosing a new scene root type.
Initialization
- ROW_HEIGHT¶
40.0
- DIALOG_WIDTH¶
320.0
- HEADER_HEIGHT¶
36.0
- show_dialog(parent_size: simvx.core.Vec2 | None = None)[source]¶
Show the dialog centered in the parent.
- style¶
‘ThemeStyleBox(…)’
- property bg_colour¶
- property border_colour¶
- property border_width¶
- get_minimum_size() simvx.core.math.types.Vec2¶
- draw(renderer)¶
- size_x¶
‘Property(…)’
- 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(…)’
- property size: simvx.core.math.types.Vec2¶
- touch_mode: str¶
‘mouse’
- property theme: simvx.core.ui.types.Theme | None¶
- property mouse_over: bool¶
- property focused: bool¶
- property disabled: bool¶
- get_theme() simvx.core.ui.types.Theme¶
- queue_redraw()¶
- get_rect() tuple[float, float, float, float]¶
- get_global_rect() tuple[float, float, float, float]¶
- is_point_inside(point) bool¶
- set_anchor_preset(preset: simvx.core.ui.enums.AnchorPreset)¶
- set_focus()¶
- grab_focus()¶
- release_focus()¶
- has_focus() bool¶
- focus_next_control()¶
- focus_previous_control()¶
- grab_mouse()¶
- release_mouse()¶
- set_drag_preview(control: simvx.core.ui.core.Control)¶
- draw_popup(renderer)¶
- is_popup_point_inside(point) bool¶
- popup_input(event)¶
- dismiss_popup()¶
- 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 position: simvx.core.math.types.Vec2¶
- property rotation: float¶
- property rotation_degrees: float¶
- property scale: simvx.core.math.types.Vec2¶
- property world_position: simvx.core.math.types.Vec2¶
- property world_rotation: float¶
- property world_scale: simvx.core.math.types.Vec2¶
- 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)¶
- strict_errors: ClassVar[bool]¶
True
- script_error_raised¶
‘Signal(…)’
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property process_mode: simvx.core.descriptors.ProcessMode¶
- property visible: bool¶
- reset_error() None¶
- add_child(node: simvx.core.node.Node) simvx.core.node.Node¶
- remove_child(node: simvx.core.node.Node)¶
- reparent(new_parent: simvx.core.node.Node)¶
- get_node(path: str) simvx.core.node.Node¶
- find_child(name: str, recursive: bool = False) simvx.core.node.Node | None¶
- find(node_type: type, recursive: bool = True) simvx.core.node.Node | None¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- ready() None¶
- enter_tree() None¶
- exit_tree() None¶
- process(dt: float) None¶
- physics_process(dt: float) None¶
- picked(event: simvx.core.events.InputEvent) None¶
- handle_input(event: simvx.core.events.TreeInputEvent) None¶
- unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- clear_children()¶
- destroy()¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶