extends SceneTree const THEME := preload("res://scripts/editors/prop/prop_theme.gd") const CANVAS_SCENE := preload("res://scenes/editors/prop/prop_editor.tscn") const PREVIEW_SCENE := preload("res://scenes/editors/prop/prop_attach_preview.tscn") const PROP_FILE := preload("res://scripts/editors/prop/prop_file.gd") var _failed: int = 0 var _count: int = 0 func _init() -> void: call_deferred("_run") func _check(label: String, value: bool) -> void: _count += 1 if value: print("PASS: %s" % label) else: _failed += 1 push_error("FAIL: %s" % label) func _run() -> void: root.size = Vector2i(1200, 800) var theme := THEME.new() _check("default inspector background uses shared surface token", theme.inspector_background_color().is_equal_approx(Color("#252B38FA"))) var preview := PREVIEW_SCENE.instantiate() as Control root.add_child(preview) await process_frame await process_frame var hand := preview.find_child("HandOption", true, false) as OptionButton var motion := preview.find_child("MotionOption", true, false) as OptionButton _check("hand labels are kid-readable", hand != null and hand.get_item_text(0) == "Left Hand" and hand.get_item_text(1) == "Right Hand") _check("motion selector has approved choices", motion != null and motion.item_count == 3 and motion.get_item_text(0) == "Front Pose" and motion.get_item_text(1) == "Walk Left" and motion.get_item_text(2) == "Walk Right") _check("obsolete preview controls removed", preview.find_child("FacingOption", true, false) == null and preview.find_child("FrameOption", true, false) == null) preview.call("set_preview_motion", 2) _check("walk right enters active gait", int(preview.get("_motion")) == 2 and not bool(preview.get("_walk_paused"))) preview.call("toggle_walk_playback") _check("walk toggle pauses gait", bool(preview.get("_walk_paused"))) preview.call("set_preview_motion", 0) _check("front pose stops gait", int(preview.get("_motion")) == 0 and bool(preview.get("_walk_paused"))) preview.queue_free() var editor := CANVAS_SCENE.instantiate() as Control root.add_child(editor) await process_frame var canvas := editor.get("_canvas") as PropCanvas var attach_tools := editor.get("_attach_tools") as FlowContainer var marker := editor.get("_inactive_anchors_check") as CheckBox _check("attach tools are wrapping flow controls", attach_tools != null) _check("marker toggle is meaningful wording", marker != null and marker.text == "Show Other Markers") canvas.set_edit_mode(PropCanvas.EditMode.ATTACH) await process_frame var material := editor.get("_material_section") as Control _check("material hides in Attach", material != null and not material.visible) canvas.set_edit_mode(PropCanvas.EditMode.TRANSFORM) _check("material returns in Arrange", material != null and material.visible) var anchors: Dictionary = {"grip": {"role": "grip", "position": Vector2(10.0, 20.0), "rotation_deg": 12.0, "z_index_offset": 2, "allowed_hands": "both"}} editor.set("_anchors", anchors) canvas.set_anchor_data(anchors) editor.call("_select_anchor", "grip") var roles := editor.get("_anchor_role") as OptionButton _check("editable role list omits pivot and maps safely", roles != null and roles.item_count == 5 and roles.get_item_text(0) == "grip" and roles.get_item_text(4) == "custom") editor.call("_on_rename_anchor_pressed") var dialog := editor.get("_rename_anchor_dialog") as ConfirmationDialog var rename_edit := editor.get("_rename_anchor_edit") as LineEdit rename_edit.text = "Main Handle" dialog.get_ok_button().emit_signal("pressed") await process_frame var renamed: Dictionary = editor.get("_anchors") _check("dialog confirmation renames normalized anchor", renamed.has("main_handle") and not renamed.has("grip") and str(renamed["main_handle"].get("role")) == "grip") renamed["other"] = {"role": "custom", "position": Vector2.ZERO, "rotation_deg": 0.0, "z_index_offset": 0, "allowed_hands": "both"} editor.set("_anchors", renamed) canvas.set_anchor_data(renamed) editor.call("_select_anchor", "other") editor.call("_on_rename_anchor_pressed") rename_edit.text = "Main Handle" dialog.get_ok_button().emit_signal("pressed") await process_frame var collision_renamed: Dictionary = editor.get("_anchors") _check("dialog confirmation uses collision suffix", collision_renamed.has("main_handle") and collision_renamed.has("main_handle_2")) editor.call("_select_anchor", "main_handle_2") editor.call("_on_rename_anchor_pressed") rename_edit.text = "Entered Name" rename_edit.text_submitted.emit(rename_edit.text) await process_frame _check("Enter in rename field confirms typed name", (editor.get("_anchors") as Dictionary).has("entered_name") and not (editor.get("_anchors") as Dictionary).has("main_handle_2")) editor.call("_select_anchor", "entered_name") editor.call("_on_rename_anchor_pressed") rename_edit.text = "Cancelled Name" dialog.emit_signal("canceled") await process_frame _check("dialog cancel leaves anchor unchanged", (editor.get("_anchors") as Dictionary).has("entered_name") and str(editor.get("_rename_anchor_source_id")).is_empty()) var main_split := editor.get("_main_layout") as HSplitContainer var inspector := editor.get("_inspector_column") as PanelContainer _check("inspector starts at minimum usable width", main_split != null and inspector != null and inspector.size.x >= inspector.get_combined_minimum_size().x) var eye_data: Dictionary = PROP_FILE.load("res://content/props/eye.prop") _check("eye prop fixture is available", not eye_data.is_empty()) editor.call("_apply_json_data", eye_data) root.size = Vector2i(1200, 600) canvas.set_edit_mode(PropCanvas.EditMode.ATTACH) await process_frame await process_frame var top_bar := editor.get_node("ChromeRoot/TopBar") as Control var status_bar := editor.get_node("ChromeRoot/StatusBar") as Control var holding_preview := editor.get("_attach_preview") as Control _check("Attach layout stays between name and status bars", main_split.get_global_rect().position.y >= top_bar.get_global_rect().end.y - 1.0 and holding_preview.get_global_rect().end.y <= status_bar.get_global_rect().position.y + 1.0) var preview_container := holding_preview.get("_viewport_container") as SubViewportContainer var preview_viewport := holding_preview.get("_viewport") as SubViewport _check("preview viewport follows flexible pane height", preview_container != null and preview_viewport != null and preview_container.size.y > 0.0 and absf(float(preview_viewport.size.y) - preview_container.size.y) <= 1.0) editor.queue_free() print("RESULT: %s (%d assertions)" % ["ALL PASSED" if _failed == 0 else "%d FAILED" % _failed, _count]) quit(0 if _failed == 0 else 1)