Add StageBackgroundView and related tests for plain background functionality

- Implemented StageBackgroundView class for managing sky and plain backgrounds in the stage.
- Added functionality to set background type and color, bind camera, and apply themes.
- Created test_phase19_plain_background.gd to validate plain background behavior and migration.
- Developed test_phase19_starter_chooser_layout.gd to ensure proper layout and functionality of the starter chooser.
- Included visual capture tests for UI elements and interactions.
This commit is contained in:
2026-10-22 16:18:25 -04:00
parent db677dc194
commit 59f1817063
43 changed files with 2403 additions and 160 deletions
+204 -25
View File
@@ -50,7 +50,7 @@ const STAGE_MODAL_VIEWS_SCRIPT := preload("res://scripts/editors/stage/stage_mod
const STAGE_THEME_CONTROLLER_SCRIPT := preload("res://scripts/editors/stage/stage_theme_controller.gd")
const STAGE_TARGET_CAPTURE_SCRIPT := preload("res://scripts/editors/stage/stage_target_capture_session.gd")
const STAGE_SCENERY_CONTROLLER_SCRIPT := preload("res://scripts/editors/stage/stage_scenery_controller.gd")
const STAGE_SKY_VIEW_SCRIPT := preload("res://scripts/stage/scenery/stage_sky_view.gd")
const STAGE_BACKGROUND_VIEW_SCRIPT := preload("res://scripts/stage/scenery/stage_background_view.gd")
const STAGE_DRAW_ORDER_SCRIPT := preload("res://scripts/stage/stage_draw_order.gd")
const STAGE_WALL_PANEL_SCRIPT := preload("res://scripts/stage/scenery/stage_wall_panel.gd")
const STAGE_BACKGROUND_GROUND_SCRIPT := preload("res://scripts/stage/scenery/stage_background_ground.gd")
@@ -258,13 +258,21 @@ var _spawner: StageSpawner
var _selection: StageSelection
var _gizmos: StageGizmos
var _stage_input_ready: bool = false
var _startup_scene_applied: bool = false
var _startup_starter_chooser_pending: bool = false
var _startup_starter_chooser_shown: bool = false
var _grid: StageGrid
var _spatial_index: StageSpatialIndex
var _terrain_painter: StageTerrainPainter
var _scenery_controller: StageSceneryController
var _sky_layer: CanvasLayer
var _sky_view: StageSkyView
var _background_view: StageBackgroundView
var _sky_id: StringName = &"sky_neutral"
var _background_kind: StringName = &"sky"
var _plain_color: Color = Color("#F5EFE0")
var _plain_color_draft_active: bool = false
var _plain_color_draft: Color = Color("#F5EFE0")
var _new_ground_finish: StringName = &"finish_ground_grass"
var _hosted_prop_editor: PropEditor
var _hosted_artwork_path: String = ""
@@ -1850,6 +1858,8 @@ func set_mode(mode: StageMode) -> void:
_show_toast("Finish or cancel speech editing first.")
_sync_mode_buttons()
return
if _plain_color_draft_active:
_close_selector()
_cancel_surface_color_preview()
if _scenery_controller != null:
if _scenery_controller.is_group_preview_pending():
@@ -2513,6 +2523,74 @@ func _mark_scene_dirty() -> void:
_paused_edit_autosave_remaining = 1.0
func _refresh_background_view() -> void:
if _background_view != null:
var displayed_color: Color = _plain_color_draft if _plain_color_draft_active else _plain_color
_background_view.set_background(_background_kind, _sky_id, displayed_color)
_sky_view = _background_view.get_sky_view()
_update_grid_background_style()
func _commit_background_kind(kind: StringName, sky_id: StringName = &"") -> void:
var next_kind: StringName = &"plain" if kind == &"plain" else &"sky"
var next_sky: StringName = sky_id if not sky_id.is_empty() else _sky_id
var changed: bool = _background_kind != next_kind or _sky_id != next_sky
_background_kind = next_kind
_sky_id = next_sky
_refresh_background_view()
if _asset_browser != null:
_asset_browser.set_background_state(_background_kind, _sky_id, _plain_color)
if changed:
_mark_scene_dirty()
func _preview_plain_color(color: Color) -> void:
_plain_color_draft = _opaque_stage_color(color)
_plain_color_draft_active = true
_refresh_background_view()
func _cancel_plain_color_preview() -> void:
if not _plain_color_draft_active:
return
_plain_color_draft_active = false
_plain_color_draft = _plain_color
_refresh_background_view()
func _commit_plain_color(color: Color) -> void:
var next_color: Color = _opaque_stage_color(color)
var changed: bool = _canonical_surface_color(_plain_color) != _canonical_surface_color(next_color)
_plain_color = next_color
_plain_color_draft = next_color
_plain_color_draft_active = false
_refresh_background_view()
_record_recent_surface_color(next_color)
if _asset_browser != null:
_asset_browser.set_background_state(_background_kind, _sky_id, _plain_color)
if changed:
_mark_scene_dirty()
func _opaque_stage_color(color: Color) -> Color:
return Color(color.r, color.g, color.b, 1.0)
func _update_grid_background_style() -> void:
if _grid == null:
return
var displayed_color: Color = _plain_color_draft if _plain_color_draft_active else _plain_color
var plain_active: bool = _background_kind == &"plain"
_grid.set_background_treatment(
plain_active,
displayed_color,
_sandbox_theme.color("grid.plain_light_minor", Color("#11182120")) if _sandbox_theme != null else Color("#11182120"),
_sandbox_theme.color("grid.plain_light_major", Color("#11182148")) if _sandbox_theme != null else Color("#11182148"),
_sandbox_theme.color("grid.plain_dark_minor", Color("#FFFFFF25")) if _sandbox_theme != null else Color("#FFFFFF25"),
_sandbox_theme.color("grid.plain_dark_major", Color("#FFFFFF58")) if _sandbox_theme != null else Color("#FFFFFF58")
)
func _set_scene_dirty(value: bool) -> void:
if _document != null:
_document.set_dirty(value)
@@ -2533,6 +2611,8 @@ func _collect_scene_data(is_autosave: bool = false) -> Dictionary:
var document_metadata: Dictionary = {
"scene_name": _scene_name,
"sky_id": String(_sky_id),
"background_kind": String(_background_kind),
"plain_color": _canonical_surface_color(_plain_color),
"metadata": _document.metadata_for_snapshot(is_autosave),
}
return _scene_adapter.collect(_world, _authored, _event_rules, camera_state, document_metadata)
@@ -2613,6 +2693,7 @@ func _validate_queues_for_save() -> String:
func _reset_scene_content() -> void:
set_mode(StageMode.EDIT)
_cancel_plain_color_preview()
_cancel_surface_color_preview()
if _scenery_erase_piece_dialog != null:
_scenery_erase_piece_dialog.hide()
@@ -2622,8 +2703,9 @@ func _reset_scene_content() -> void:
_cancel_scenery_repair_preview()
_scenery_repair_target = null
_sky_id = &"sky_neutral"
if _sky_view != null:
_sky_view.set_sky(_sky_id)
_background_kind = &"sky"
_plain_color = Color("#F5EFE0")
_refresh_background_view()
if _scenery_controller != null:
_scenery_controller.exit_tool()
_scenery_controller.cancel_group()
@@ -2655,11 +2737,19 @@ func _apply_scene_data(data: Dictionary, source_path: String, is_recovery: bool)
source_path = CONTENT_PATHS.canonicalize(source_path)
if _scene_adapter == null:
return false
if _plain_color_draft_active:
_close_selector()
_cancel_plain_color_preview()
var was_suppressed: bool = _suppress_dirty
_suppress_dirty = true
_reset_scene_content()
var adapter_result: Dictionary = _scene_adapter.apply(data, _world, _spawner)
_sky_id = StringName(String(adapter_result.get("sky_id", "sky_neutral")))
_background_kind = StringName(String(adapter_result.get("background_kind", "sky")))
_plain_color = STAGE_SCENE_IO.color_from_data(
adapter_result.get("plain_color", STAGE_SCENE_IO.DEFAULT_PLAIN_COLOR),
Color("#F5EFE0")
)
var loaded_nodes: Array[Node2D] = adapter_result.get("loaded_nodes", [])
for node: Node2D in loaded_nodes:
_finalize_placed_node(node)
@@ -2683,8 +2773,7 @@ func _apply_scene_data(data: Dictionary, source_path: String, is_recovery: bool)
var camera_data: Dictionary = raw_camera as Dictionary if raw_camera is Dictionary else {}
_camera.global_position = STAGE_SCENE_IO.data_to_vector(camera_data.get("position"), DEFAULT_CAMERA_POSITION)
_camera.zoom = Vector2.ONE * clampf(float(camera_data.get("zoom", DEFAULT_CAMERA_ZOOM)), min_zoom, max_zoom)
if _sky_view != null:
_sky_view.set_sky(_sky_id)
_refresh_background_view()
var raw_metadata: Variant = data.get("metadata", {})
var metadata: Dictionary = raw_metadata as Dictionary if raw_metadata is Dictionary else {}
if _document != null:
@@ -2712,6 +2801,7 @@ func _apply_scene_data(data: Dictionary, source_path: String, is_recovery: bool)
_add_recent_scene(source_path)
if _document != null:
_document.remove_autosave()
_startup_scene_applied = true
return true
func _show_scene_load_warnings(warnings: Array[String]) -> void:
@@ -2782,20 +2872,79 @@ func _update_scene_chrome() -> void:
_refresh_status()
func _check_autosave_recovery() -> void:
func _check_autosave_recovery(show_starter_chooser_after_discard: bool = false) -> void:
if _document == null:
if show_starter_chooser_after_discard:
_queue_startup_starter_chooser()
return
var inspection: Dictionary = _document.inspect_autosave()
if not bool(inspection.get("available", false)):
if show_starter_chooser_after_discard:
_queue_startup_starter_chooser()
return
var autosave_data: Dictionary = inspection.get("data", {}) as Dictionary
var dialog := ConfirmationDialog.new()
dialog.name = "AutosaveRecoveryDialog"; dialog.title = "Recover Sandbox Scene?"; dialog.dialog_text = "A previous Play session was not closed cleanly. Recover it?"
dialog.confirmed.connect(func() -> void: _apply_scene_data(autosave_data, AUTOSAVE_PATH, true); dialog.queue_free())
dialog.canceled.connect(func() -> void: _document.remove_autosave(); dialog.queue_free())
dialog.canceled.connect(func() -> void:
_document.remove_autosave()
dialog.queue_free()
if show_starter_chooser_after_discard:
_queue_startup_starter_chooser()
)
get_node(NodePath("UI")).add_child(dialog); _apply_dialog_theme(dialog); dialog.popup_centered()
func _queue_startup_starter_chooser() -> void:
if _startup_starter_chooser_pending or _startup_starter_chooser_shown:
return
_startup_starter_chooser_pending = true
call_deferred("_present_startup_starter_chooser")
func _present_startup_starter_chooser() -> void:
while _startup_starter_chooser_pending and is_inside_tree():
if not _stage_input_ready or _startup_modal_is_visible():
await get_tree().process_frame
continue
if get_tree().current_scene != self or _startup_scene_applied or current_mode != StageMode.EDIT or not _current_scene_path.is_empty() or _hosted_prop_editor != null:
_startup_starter_chooser_pending = false
return
_startup_starter_chooser_pending = false
_startup_starter_chooser_shown = true
_open_selector("starters")
return
_startup_starter_chooser_pending = false
func _startup_modal_is_visible() -> bool:
if _selector_open or _speech_composer_is_open():
return true
var ui_layer: CanvasLayer = _chrome.get_canvas_layer() if _chrome != null else null
if ui_layer != null:
for child: Node in ui_layer.get_children():
var window := child as Window
if window != null and window.visible:
return true
for dialog: Window in [
_cli_error_dialog,
_speech_recovery_dialog,
_speech_save_gate_dialog,
_scene_open_dialog,
_scene_save_dialog,
_unsaved_changes_dialog,
_rename_scene_dialog,
_missing_assets_dialog,
_missing_scenery_dialog,
_scenery_repair_confirm_dialog,
_group_preview_save_dialog,
_confirm_dialog,
]:
if dialog != null and is_instance_valid(dialog) and dialog.visible:
return true
return false
func _handle_cli_startup(args: Array) -> void:
if OS.get_environment("STICKMAN_WALK_DEBUG") == "1":
print("[WalkDebug] CLI_STARTUP args=%s" % [args])
@@ -2806,7 +2955,7 @@ func _handle_cli_startup(args: Array) -> void:
return
var scene_path := String(result.get("scene_path", ""))
if scene_path.is_empty():
_check_autosave_recovery()
_check_autosave_recovery(true)
return
if _document != null and _document.has_autosave():
_document.remove_autosave()
@@ -3085,6 +3234,9 @@ func _build_ui() -> void:
_asset_browser.asset_selected_requested.connect(_on_asset_selected)
_asset_browser.selector_cancel_requested.connect(_on_selector_cancelled)
_asset_browser.plain_color_preview_requested.connect(_preview_plain_color)
_asset_browser.plain_color_commit_requested.connect(_commit_plain_color)
_asset_browser.plain_color_preview_cancel_requested.connect(_cancel_plain_color_preview)
_asset_browser.asset_load_failed.connect(func(kind: String, path: String) -> void:
if _scenery_repair_target != null and is_instance_valid(_scenery_repair_target):
_show_toast("Could not open that artwork. Try another file.")
@@ -3097,6 +3249,7 @@ func _build_ui() -> void:
_asset_browser.edit_scenery_requested.connect(_enter_scenery_edit_mode)
_asset_browser.surface_color_confirmed.connect(_record_recent_surface_color)
_asset_browser.set_surface_color_history(_recent_surface_colors)
_asset_browser.set_background_state(_background_kind, _sky_id, _plain_color)
_build_ground_finish_popup(ui)
_modal_views.build_file_dialogs(ui)
@@ -4510,6 +4663,8 @@ func _build_gizmo_layer() -> void:
_gizmos = STAGE_GIZMOS.new()
_gizmos.name = "GizmoLayer"
_gizmos.camera = _camera
if _sandbox_theme != null:
_gizmos.apply_theme(_sandbox_theme as SandboxTheme)
_gizmos.transform_committed.connect(_on_transform_committed)
_gizmos.transform_started.connect(_on_gizmo_transform_started)
_gizmos.transform_updated.connect(_on_gizmo_transform_updated)
@@ -4522,6 +4677,7 @@ func _build_grid_layer() -> void:
_grid.camera = _camera
add_child(_grid)
move_child(_grid, 0)
_update_grid_background_style()
func _build_ghost_holder() -> void:
@@ -4542,15 +4698,19 @@ func _build_scenery_controller() -> void:
func _build_sky_layer() -> void:
_sky_layer = CanvasLayer.new()
_sky_layer.name = "StageSkyLayer"
_sky_layer.name = "StageBackgroundLayer"
_sky_layer.layer = -1
_sky_view = STAGE_SKY_VIEW_SCRIPT.new() as StageSkyView
_sky_view.name = "StageSkyView"
_sky_view.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_sky_view.set_sky(_sky_id)
_sky_layer.add_child(_sky_view)
_background_view = STAGE_BACKGROUND_VIEW_SCRIPT.new() as StageBackgroundView
_background_view.name = "StageBackgroundView"
_background_view.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_background_view.set_background(_background_kind, _sky_id, _plain_color)
_sky_layer.add_child(_background_view)
add_child(_sky_layer)
_sky_view.bind_camera(_camera)
_background_view.bind_camera(_camera)
_sky_view = _background_view.get_sky_view()
if _sandbox_theme != null:
_background_view.apply_theme(_sandbox_theme as SandboxTheme)
_update_grid_background_style()
func _build_placement_overlay() -> void:
@@ -4912,7 +5072,13 @@ func _open_selector(kind: String) -> void:
(_palette_buttons[pid] as Button).set_pressed_no_signal(pid == kind)
if kind == "scenery":
_asset_browser.set_surface_color_history(_recent_surface_colors)
var selector_state: Dictionary = _asset_browser.open_selector(kind, _spawner.get_selected_stickman_path(), _sky_id)
var selector_state: Dictionary = _asset_browser.open_selector(
kind,
_spawner.get_selected_stickman_path(),
_sky_id,
_background_kind,
_plain_color
)
if kind == "stickman":
var selected_stickman_path: String = String(selector_state.get("selected_stickman_path", _spawner.get_selected_stickman_path()))
if selected_stickman_path != _spawner.get_selected_stickman_path():
@@ -4940,12 +5106,14 @@ func _on_asset_selected(entry: Dictionary) -> void:
return
var background_kind: String = String(entry.get("background_kind", ""))
if background_kind == "sky":
_sky_id = StringName(String(entry.get("id", "sky_neutral")))
_sky_view.set_sky(_sky_id)
var scenery_selector: AssetSelector = _asset_browser.get_selector()
if scenery_selector != null:
scenery_selector.set_current_sky(_sky_id)
_mark_scene_dirty()
_commit_background_kind(&"sky", StringName(String(entry.get("id", "sky_neutral"))))
_refresh_scenery_capture_bar()
return
if background_kind == "plain":
_commit_background_kind(&"plain")
var plain_selector: AssetSelector = _asset_browser.get_selector()
if plain_selector != null:
plain_selector.open_plain_background_choices(_plain_color)
_refresh_scenery_capture_bar()
return
if background_kind == "wall":
@@ -5774,8 +5942,15 @@ func _handle_scenery_edit_motion(world_position: Vector2) -> void:
func _close_selector() -> void:
var closing_kind: String = _selector_kind
_cancel_plain_color_preview()
if _asset_browser != null:
_asset_browser.close()
if closing_kind == "scenery":
# Scenery is a chooser entry; the capture bar communicates active drawing tools.
var scenery_button: Button = _palette_buttons.get("scenery") as Button
if scenery_button != null:
scenery_button.set_pressed_no_signal(false)
func _on_selector_cancelled() -> void:
@@ -5783,7 +5958,7 @@ func _on_selector_cancelled() -> void:
return
var kind: String = _selector_kind
_close_selector()
if kind != "scenery" and kind != "starters":
if kind != "starters":
set_placement_mode("")
@@ -7900,8 +8075,12 @@ func _load_font(path: String) -> Font:
return _theme_controller.load_font(path)
func _apply_theme_to_visuals() -> void:
if _sky_view != null and _sandbox_theme != null:
_sky_view.apply_theme(_sandbox_theme as SandboxTheme)
if _background_view != null and _sandbox_theme != null:
_background_view.apply_theme(_sandbox_theme as SandboxTheme)
if _grid != null:
_update_grid_background_style()
if _gizmos != null and _sandbox_theme != null:
_gizmos.apply_theme(_sandbox_theme as SandboxTheme)
if _director_visuals != null:
_director_visuals.set_style(_theme)
_director_visuals.completed_path_alpha = _sandbox_theme.number("overlays.completed_path_alpha", 0.20, 0.0, 1.0) if _sandbox_theme != null else 0.20
+51 -5
View File
@@ -9,6 +9,9 @@ signal refresh_requested
signal make_artwork_requested
signal edit_scenery_requested
signal surface_color_confirmed(color: Color)
signal plain_color_preview_requested(color: Color)
signal plain_color_commit_requested(color: Color)
signal plain_color_preview_cancel_requested()
const ASSET_SELECTOR_SCENE := preload("res://scenes/stage/asset_selector.tscn")
const STICKMAN_LIBRARY_SCRIPT := preload("res://scripts/characters/stickman/stickman_library.gd")
@@ -32,6 +35,9 @@ var browse_dialog: FileDialog
var thumbnail_queue: Array[Dictionary] = []
var thumbnail_busy: bool = false
var thumbnail_generation: int = 0
var _current_background_kind: StringName = &"sky"
var _current_sky_id: StringName = &"sky_neutral"
var _current_plain_color: Color = Color("#F5EFE0")
func _ready() -> void:
@@ -62,6 +68,10 @@ func build_ui(ui_layer: CanvasLayer, ui_font: Font, emoji_font: Font, sandbox_th
selector.make_artwork_requested.connect(func() -> void: make_artwork_requested.emit())
selector.edit_scenery_requested.connect(func() -> void: edit_scenery_requested.emit())
selector.surface_color_confirmed.connect(func(color: Color) -> void: surface_color_confirmed.emit(color))
selector.plain_color_preview_requested.connect(func(color: Color) -> void: plain_color_preview_requested.emit(color))
selector.plain_color_commit_requested.connect(func(color: Color) -> void: plain_color_commit_requested.emit(color))
selector.plain_color_preview_cancel_requested.connect(func() -> void: plain_color_preview_cancel_requested.emit())
selector.stage_preview_dimming_changed.connect(_on_selector_stage_preview_dimming_changed)
ui_layer.add_child(selector)
# apply_font AFTER add_child so the selector's @onready nodes resolve first.
selector.apply_font(ui_font, emoji_font)
@@ -92,12 +102,28 @@ func set_surface_color_history(colors: Array[Color]) -> void:
selector.set_surface_color_history(colors)
func set_background_state(kind: StringName, sky_id: StringName, plain_color: Color) -> void:
_current_background_kind = &"plain" if kind == &"plain" else &"sky"
_current_sky_id = sky_id
_current_plain_color = Color(plain_color.r, plain_color.g, plain_color.b, 1.0)
if selector != null:
selector.set_background_state(_current_background_kind, _current_sky_id, _current_plain_color)
func _starter_scene_entries() -> Array[Dictionary]:
return [
{
"id": "starter_plain_background",
"name": "Plain Background",
"description": "An empty stage with one color. Choose a new color whenever you like.",
"category": "Make your own",
"path": "res://content/stages/starters/plain_background.scene",
"icon": "🎨",
},
{
"id": "starter_blank_scene",
"name": "Blank Scene",
"description": "Start fresh with an open stage and a clear sky.",
"name": "Open Sky",
"description": "An empty stage with a soft sky. Sun and clouds, ready for your story.",
"category": "Make your own",
"path": "res://content/stages/starters/blank.scene",
"icon": "✨",
@@ -129,7 +155,16 @@ func make_browse_entry(kind: String, path: String) -> Dictionary:
return stickman_library.make_entry(path)
func open_selector(kind: String, current_stickman_path: String, current_sky_id: StringName = &"") -> Dictionary:
func open_selector(
kind: String,
current_stickman_path: String,
current_sky_id: StringName = &"",
background_kind: StringName = &"sky",
plain_color: Color = Color("#F5EFE0")
) -> Dictionary:
_current_background_kind = &"plain" if background_kind == &"plain" else &"sky"
_current_sky_id = current_sky_id if not current_sky_id.is_empty() else &"sky_neutral"
_current_plain_color = Color(plain_color.r, plain_color.g, plain_color.b, 1.0)
set_selector_kind(kind)
var entries: Array[Dictionary] = scan_entries(kind)
if kind == "starters":
@@ -142,7 +177,7 @@ func open_selector(kind: String, current_stickman_path: String, current_sky_id:
selected_stickman_path = String(entries[0].get("path", ""))
var auto_selection: Dictionary = entries[0] if kind == "stickman" and entries.size() == 1 else {}
if auto_selection.is_empty():
open(kind, entries, current_sky_id)
open(kind, entries, _current_sky_id)
return {
"entries": entries,
"selected_stickman_path": selected_stickman_path,
@@ -152,6 +187,7 @@ func open_selector(kind: String, current_stickman_path: String, current_sky_id:
func _scenery_background_entries() -> Array[Dictionary]:
return [
{"id": "plain_background", "name": "Plain Background", "category": "Scene background", "gallery_tab": "backgrounds", "background_kind": "plain", "plain_color": _current_plain_color, "icon": "🎨"},
{"id": "sky_clear_day", "name": "Clear Day", "category": "Sky", "gallery_tab": "backgrounds", "background_kind": "sky", "icon": "☀️"},
{"id": "sky_cloudy_day", "name": "Cloudy Day", "category": "Sky", "gallery_tab": "backgrounds", "background_kind": "sky", "icon": "☁️"},
{"id": "sky_sunset", "name": "Sunset", "category": "Sky", "gallery_tab": "backgrounds", "background_kind": "sky", "icon": "🌅"},
@@ -170,8 +206,9 @@ func open(kind: String, entries: Array[Dictionary], current_sky_id: StringName =
selector_open = true
if selector_dim != null:
selector_dim.visible = true
selector_dim.color = Color(0.0, 0.0, 0.0, SELECTOR_DIM_ALPHA)
if selector != null:
selector.open(kind, entries, String(current_sky_id))
selector.open(kind, entries, String(current_sky_id), String(_current_background_kind), _current_plain_color)
load_or_enqueue_thumbnails(kind, entries)
@@ -206,6 +243,8 @@ func set_entries(entries: Array[Dictionary]) -> void:
func refresh_selector_entries() -> Array[Dictionary]:
var entries: Array[Dictionary] = scan_entries(selector_kind)
if selector_kind == "scenery":
entries.append_array(_scenery_background_entries())
set_entries(entries)
return entries
@@ -282,6 +321,13 @@ func _on_selector_cancelled() -> void:
selector_cancel_requested.emit()
func _on_selector_stage_preview_dimming_changed(should_dim: bool) -> void:
if selector_dim == null:
return
selector_dim.color = Color(0.0, 0.0, 0.0, SELECTOR_DIM_ALPHA if should_dim else 0.0)
selector_dim.visible = selector_open
func _on_selector_popup_hide() -> void:
if not selector_open:
return
@@ -130,6 +130,8 @@ func collect(
"version": STAGE_SCENE_IO.FILE_VERSION,
"scene_name": scene_name,
"sky_id": String(document_metadata.get("sky_id", "sky_neutral")),
"background_kind": String(document_metadata.get("background_kind", "sky")),
"plain_color": String(document_metadata.get("plain_color", STAGE_SCENE_IO.DEFAULT_PLAIN_COLOR)),
"camera": {"position": STAGE_SCENE_IO.vector_to_data(camera_position), "zoom": camera_zoom},
"objects": objects,
"event_rules": rules_result["rules"],
@@ -299,6 +301,8 @@ func apply(data: Dictionary, world: Node2D, spawner: StageSpawner) -> Dictionary
"missing_paths": missing_paths,
"decoded_rules": decoded_rules,
"sky_id": String(data.get("sky_id", "sky_neutral")),
"background_kind": String(data.get("background_kind", "sky")),
"plain_color": String(data.get("plain_color", STAGE_SCENE_IO.DEFAULT_PLAIN_COLOR)),
}