"""Auto-split from the former flat demo_steps.py."""
import logging
from dataclasses import dataclass, field
log = logging.getLogger(__name__)
[docs]
@dataclass
class AddNode:
"""Add a node to the scene via state.add_node()."""
type_name: str
parent_path: str = ""
name: str = ""
[docs]
@dataclass
class RenameNode:
"""Rename a node via state.rename_node()."""
path: str
new_name: str
[docs]
@dataclass
class SelectNode:
"""Select a node via state.selection.select()."""
path: str
[docs]
@dataclass
class SetProperty:
"""Set a Property-descriptor value via state.set_node_property()."""
path: str
prop: str
value: object
[docs]
@dataclass
class AssertProperty:
"""Assert a node property equals expected, with actual-value diagnostics."""
path: str
prop: str
expected: object
tolerance: float = 0.5
message: str = ""
[docs]
@dataclass
class SetScript:
"""Set the code viewport text via state.set_script_text()."""
text: str
[docs]
@dataclass
class PlayScene:
"""Enter play mode via state.play_scene()."""
[docs]
@dataclass
class StopScene:
"""Exit play mode via state.stop_scene()."""
[docs]
@dataclass
class SwitchViewport:
"""Switch viewport mode (\"3d\", \"2d\", or \"code\")."""
mode: str
[docs]
@dataclass
class AssertTree:
"""Verify scene tree structure.
*expected* maps path -> type_name or path -> (type_name, child_count).
"""
expected: dict
message: str = ""
[docs]
@dataclass
class PlaceNode:
"""Add a node at a specific position (mouse-placement style)."""
type_name: str
x: float = 0.0
y: float = 0.0
parent_path: str = ""
name: str = ""
[docs]
@dataclass
class AssertConfig:
"""Verify multiple properties on a node match expected values."""
path: str
props: dict = field(default_factory=dict)
message: str = ""
[docs]
@dataclass
class DialogSelect:
"""Type filter text and click a type row in the open Add Node dialog."""
type_name: str
_phase: int = field(default=0, init=False, repr=False)
_char_idx: int = field(default=0, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class ClickTreeItem:
"""Click a node in the scene tree by path to select it."""
path: str
_phase: int = field(default=0, init=False, repr=False)
_retried: bool = field(default=False, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class InspectorRename:
"""Click the inspector name field and type a new name."""
new_name: str
_phase: int = field(default=0, init=False, repr=False)
_char_idx: int = field(default=0, init=False, repr=False)
_cleared: int = field(default=0, init=False, repr=False)
_clear_count: int = field(default=0, init=False, repr=False)
_edit_ref: object = field(default=None, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class InspectorEdit:
"""Edit a property via the inspector widget (SpinBox, TextEdit, or Slider)."""
prop: str
value: object
component: int = -1 # For VectorRow: 0=X, 1=Y, 2=Z; -1=direct widget
_phase: int = field(default=0, init=False, repr=False)
_char_idx: int = field(default=0, init=False, repr=False)
_cleared: int = field(default=0, init=False, repr=False)
_clear_count: int = field(default=0, init=False, repr=False)
_widget_ref: object = field(default=None, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class InspectorSetColour:
"""Set a colour via the inspector ColourPicker hex input (click hex field, type value, enter)."""
prop: str
colour: tuple
_phase: int = field(default=0, init=False, repr=False)
_char_idx: int = field(default=0, init=False, repr=False)
_cleared: int = field(default=0, init=False, repr=False)
_clear_count: int = field(default=0, init=False, repr=False)
_widget_ref: object = field(default=None, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class InspectorSetAnchorPreset:
"""Expand the anchor-preset widget and click the named preset button.
preset: the AnchorPreset enum member name, e.g. "CENTER", "FULL_RECT",
"TOP_LEFT". Mirrors driving the UI a user would use: the demo expands
the preset grid, clicks the preset, and the grid collapses.
"""
preset: str
_phase: int = field(default=0, init=False, repr=False)
_widget_ref: object = field(default=None, init=False, repr=False)
_retry_count: int = field(default=0, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class PasteInEditor:
"""Paste content into the active code editor via clipboard + Ctrl+A/Ctrl+V."""
content: str
_phase: int = field(default=0, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class ClickViewport3D:
"""Click at a 3D world position in the viewport during play mode.
Projects world_pos to screen coordinates using the playing scene's camera,
moves the cursor there, and calls input_cast() for 3D picking.
"""
world_pos: tuple[float, float, float]
_phase: int = field(default=0, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class ClickGameNode:
"""Click a node in the running game's isolated SceneTree by path.
Resolves ``path`` against ``play_mode.game_tree.root`` (Godot-style
relative path, e.g. ``"Layout/Grid/Cell_0_0"``), reads the node's
global rect in game-space, and maps it back through the editor
viewport rect to editor screen coordinates so the simulated click
routes correctly through the viewport panel's input forwarder.
"""
path: str
_phase: int = field(default=0, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class ClickBottomTab:
"""Click a tab in the editor's bottom-panel TabContainer by name.
Routes through the tab bar's pointer-handler the same way a user click
would, so `tab_changed` fires and the active tab updates via the
public API instead of `tabs.current_tab = i` mutation.
"""
name: str
_phase: int = field(default=0, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class DragGizmoAxis:
"""Drag a 2D translate gizmo axis handle and verify the node moved.
Selects ``path``, switches the gizmo to TRANSLATE mode, then drags the
named axis handle ("x" or "y") by ``delta`` canvas pixels via simulated
mouse input. Verifies the selected node's position changed by the expected
delta along that axis (the other axis stays fixed, as the gizmo constrains).
"""
path: str
axis: str = "x" # "x" or "y"
delta: float = 40.0 # canvas-pixel distance to drag along the axis
tolerance: float = 2.0
_phase: int = field(default=0, init=False, repr=False)
_start_pos: object = field(default=None, init=False, repr=False)
_expected: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_end: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class DoubleClickFile:
"""Double-click a file row in the file browser and verify it activated.
Resolves the file browser's TreeItem whose path basename matches
``filename``, double-clicks its row via simulated mouse input, and verifies
the panel emitted ``file_activated`` / ``file_opened`` for that path (the
item "opened").
"""
filename: str
_phase: int = field(default=0, init=False, repr=False)
_activated: list = field(default_factory=list, init=False, repr=False)
_panel_ref: object = field(default=None, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class ClickCodeCaret:
"""Click in the code editor and verify the caret moved to that position.
Clicks at the screen position of text (``line``, ``col``) in the active
code editor via simulated mouse input. The editor resolves the pending
click to a caret position on its next draw; this step renders one frame
through the tree so that resolution runs, then verifies the editor's
``_cursor_line`` / ``_cursor_col`` landed on the clicked location.
"""
line: int
col: int
_phase: int = field(default=0, init=False, repr=False)
_editor_ref: object = field(default=None, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)
[docs]
@dataclass
class NewSceneSelect:
"""Click a row in the NewSceneDialog to choose a root type."""
root_type: str # "3D Scene", "2D Scene", "UI Scene", "Empty"
_phase: int = field(default=0, init=False, repr=False)
_mc_target: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_origin: tuple = field(default=(0.0, 0.0), init=False, repr=False)
_mc_phase: int = field(default=0, init=False, repr=False)
_mc_t: float = field(default=0.0, init=False, repr=False)