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:
@@ -0,0 +1,430 @@
|
||||
extends SceneTree
|
||||
|
||||
const SANDBOX_STAGE: PackedScene = preload("res://scenes/stage/sandbox_stage.tscn")
|
||||
const STAGE_SCENE_IO: Script = preload("res://scripts/stage/stage_scene_io.gd")
|
||||
const PLAIN_STARTER_PATH: String = "res://content/stages/starters/plain_background.scene"
|
||||
|
||||
var _checks: int = 0
|
||||
var _failures: int = 0
|
||||
var _stage: SandboxStage
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
root.size = Vector2i(1280, 720)
|
||||
_test_version_migration_and_validation()
|
||||
var starter_result: Dictionary = STAGE_SCENE_IO.read_file(PLAIN_STARTER_PATH)
|
||||
_expect(bool(starter_result.get("ok", false)), "Plain Background starter is valid v1.7 data")
|
||||
_stage = SANDBOX_STAGE.instantiate() as SandboxStage
|
||||
root.add_child(_stage)
|
||||
await process_frame
|
||||
await process_frame
|
||||
_test_live_backdrop_default()
|
||||
await _save_visual_capture("phase19_open_sky_stage.png")
|
||||
await _test_plain_background_picker_flow()
|
||||
await _test_draft_cancel_on_mode_switch()
|
||||
await _test_draft_cancel_on_popup_hide()
|
||||
await _test_draft_cancel_on_scene_replacement(starter_result.get("data", {}) as Dictionary)
|
||||
_test_recent_color_history_limit()
|
||||
print("----------------------------------------")
|
||||
if _failures == 0:
|
||||
print("RESULT: ALL PASSED (%d checks)" % _checks)
|
||||
quit(0)
|
||||
else:
|
||||
print("RESULT: %d FAILURE(S) out of %d checks" % [_failures, _checks])
|
||||
quit(1)
|
||||
|
||||
|
||||
func _expect(condition: bool, message: String) -> void:
|
||||
_checks += 1
|
||||
if condition:
|
||||
print("PASS: " + message)
|
||||
else:
|
||||
_failures += 1
|
||||
push_error("Phase 19 Plain Background check failed: " + message)
|
||||
|
||||
|
||||
func _test_version_migration_and_validation() -> void:
|
||||
for version: String in ["1.0", "1.4", "1.5", "1.6"]:
|
||||
var legacy: Dictionary = {
|
||||
"version": version,
|
||||
"scene_name": "Migration fixture",
|
||||
"sky_id": "sky_sunset",
|
||||
"camera": {"position": {"x": 0.0, "y": -400.0}, "zoom": 0.5},
|
||||
"objects": [],
|
||||
"event_rules": [],
|
||||
}
|
||||
var migrated: Dictionary = STAGE_SCENE_IO._migrate_to_current(legacy)
|
||||
var expected_sky: String = "sky_sunset" if version in ["1.5", "1.6"] else "sky_neutral"
|
||||
_expect(String(migrated.get("version", "")) == "1.7", "%s scene migrates to v1.7" % version)
|
||||
_expect(String(migrated.get("sky_id", "")) == expected_sky, "%s migration preserves the compatible Sky choice" % version)
|
||||
_expect(String(migrated.get("background_kind", "")) == "sky", "%s migration remains visually Sky-backed" % version)
|
||||
_expect(String(migrated.get("plain_color", "")) == STAGE_SCENE_IO.DEFAULT_PLAIN_COLOR, "%s migration adds the default remembered color" % version)
|
||||
_expect(bool(STAGE_SCENE_IO._validate_root(migrated).get("ok", false)), "%s migrated empty scene passes v1.7 root validation" % version)
|
||||
|
||||
var valid: Dictionary = _valid_document()
|
||||
_expect(bool(STAGE_SCENE_IO._validate_root(valid).get("ok", false)), "valid v1.7 Plain Background fields pass validation")
|
||||
var missing_kind: Dictionary = valid.duplicate(true)
|
||||
missing_kind.erase("background_kind")
|
||||
_expect(not bool(STAGE_SCENE_IO._validate_root(missing_kind).get("ok", false)), "v1.7 rejects a missing background kind")
|
||||
var missing_sky: Dictionary = valid.duplicate(true)
|
||||
missing_sky.erase("sky_id")
|
||||
_expect(not bool(STAGE_SCENE_IO._validate_root(missing_sky).get("ok", false)), "v1.7 rejects a missing remembered Sky")
|
||||
var missing_color: Dictionary = valid.duplicate(true)
|
||||
missing_color.erase("plain_color")
|
||||
_expect(not bool(STAGE_SCENE_IO._validate_root(missing_color).get("ok", false)), "v1.7 rejects a missing remembered Plain Background color")
|
||||
var alpha_color: Dictionary = valid.duplicate(true)
|
||||
alpha_color["plain_color"] = "#F5EFE0FF"
|
||||
_expect(not bool(STAGE_SCENE_IO._validate_root(alpha_color).get("ok", false)), "v1.7 rejects alpha-bearing Plain Background colors")
|
||||
var bad_color: Dictionary = valid.duplicate(true)
|
||||
bad_color["plain_color"] = "F5EFE0"
|
||||
_expect(not bool(STAGE_SCENE_IO._validate_root(bad_color).get("ok", false)), "v1.7 requires canonical hash-prefixed six-digit color")
|
||||
|
||||
|
||||
func _test_live_backdrop_default() -> void:
|
||||
var background: StageBackgroundView = _stage.get("_background_view") as StageBackgroundView
|
||||
var sky_view: StageSkyView = _stage.get("_sky_view") as StageSkyView
|
||||
var plain_fill: ColorRect = background.get_node("PlainFill") as ColorRect if background != null else null
|
||||
_expect(background != null and sky_view != null and plain_fill != null, "live Stage owns the shared Sky and Plain renderer")
|
||||
if background == null or sky_view == null or plain_fill == null:
|
||||
return
|
||||
_expect(background.get_background_kind() == &"sky" and sky_view.visible and not plain_fill.visible, "default live Stage shows Sky with Plain fill hidden")
|
||||
_expect(background.get_plain_color().to_html(false).to_upper() == "F5EFE0", "default remembered Plain color is warm off-white")
|
||||
var plain_starter: Dictionary = STAGE_SCENE_IO.read_file(PLAIN_STARTER_PATH).get("data", {}) as Dictionary
|
||||
_expect(String(plain_starter.get("background_kind", "")) == "plain", "Plain Background starter selects a flat backdrop")
|
||||
_expect(String(plain_starter.get("plain_color", "")) == "#F5EFE0" and (plain_starter.get("objects", []) as Array).is_empty(), "Plain Background starter is empty and uses the approved color")
|
||||
|
||||
|
||||
func _test_plain_background_picker_flow() -> void:
|
||||
var browser: StageAssetBrowser = _stage.get("_asset_browser") as StageAssetBrowser
|
||||
_stage.call("_open_selector", "scenery")
|
||||
var selector: AssetSelector = browser.get_selector()
|
||||
selector.call("_set_gallery_tab", "backgrounds")
|
||||
await process_frame
|
||||
var grid: GridContainer = selector.find_child("GridContainer", true, false) as GridContainer
|
||||
var plain_card: AssetCard = _find_card(grid, "plain_background")
|
||||
_expect(selector.visible and plain_card != null, "real Scenery gallery shows the Plain Background card")
|
||||
if plain_card == null:
|
||||
return
|
||||
await _activate_card(plain_card)
|
||||
var title: Label = selector.find_child("TitleLabel", true, false) as Label
|
||||
var controls: StageSurfaceColorControls = selector.find_child("PlainBackgroundColorControls", true, false) as StageSurfaceColorControls
|
||||
_expect(String(_stage.get("_background_kind")) == "plain" and selector.visible, "Plain card immediately switches the Stage and keeps the gallery open")
|
||||
_expect(title != null and title.text == "Choose background color", "Plain color choices use the approved heading")
|
||||
_expect(controls != null and controls.get("_current_chip") != null, "color choices expose the current-color chip and swatch sections")
|
||||
if controls == null:
|
||||
return
|
||||
await _save_visual_capture("phase19_plain_color_choices.png")
|
||||
var recent_before: Array[String] = _stage.call("_surface_color_history_strings") as Array[String]
|
||||
_expect(not recent_before.has("#F5EFE0"), "opening at the default does not add that color to recents")
|
||||
var empty_message: Label = controls.find_child("RecentColorsEmptyLabel", true, false) as Label
|
||||
if recent_before.is_empty():
|
||||
_expect(empty_message != null and empty_message.text == "Colors you use will appear here.", "empty recent colors use the approved helper text")
|
||||
var confirmed_color: Color = _stage.get("_plain_color") as Color
|
||||
var confirmed_hex: String = _stage.call("_canonical_surface_color", confirmed_color) as String
|
||||
var dirty_before: bool = bool(_stage.get("_dirty"))
|
||||
var current_chip: Button = controls.get("_current_chip") as Button
|
||||
await _activate_button(current_chip)
|
||||
var picker_view: StageSurfaceColorPickerView = selector.get("_color_picker_view") as StageSurfaceColorPickerView
|
||||
var picker: ColorPicker = picker_view.find_child("ColorPickerControl", true, false) as ColorPicker if picker_view != null else null
|
||||
var use_button: Button = selector.get("_color_use_button") as Button
|
||||
var back_button: Button = selector.get("_color_back_button") as Button
|
||||
_expect(picker != null and use_button != null and back_button != null, "current-color chip opens the full custom picker with Back and Use color")
|
||||
if picker == null or use_button == null or back_button == null:
|
||||
return
|
||||
var draft_color: Color = Color("#B34FD8")
|
||||
_set_picker_draft(picker_view, picker, draft_color)
|
||||
await process_frame
|
||||
var background: StageBackgroundView = _stage.get("_background_view") as StageBackgroundView
|
||||
var plain_fill: ColorRect = background.get_node("PlainFill") as ColorRect
|
||||
var draft_snapshot: Dictionary = _stage.call("_collect_scene_data", false) as Dictionary
|
||||
_expect(bool(_stage.get("_plain_color_draft_active")) and plain_fill.color.to_html(false).to_upper() == "B34FD8", "custom picker movement previews an opaque flat color on the Stage")
|
||||
await _save_visual_capture("phase19_plain_picker_draft.png")
|
||||
_expect(String(draft_snapshot.get("plain_color", "")) == confirmed_hex, "scene snapshots keep the confirmed color during a custom draft")
|
||||
_expect(bool(_stage.get("_dirty")) == dirty_before and (_stage.call("_surface_color_history_strings") as Array[String]) == recent_before, "custom preview does not change dirty state or recents")
|
||||
await _activate_button(back_button)
|
||||
_expect(not bool(_stage.get("_plain_color_draft_active")) and plain_fill.color.to_html(false).to_upper() == confirmed_hex.trim_prefix("#"), "Back discards the draft and restores the confirmed Stage fill")
|
||||
await _save_visual_capture("phase19_plain_picker_rollback.png")
|
||||
_expect(bool(_stage.get("_dirty")) == dirty_before and (_stage.call("_surface_color_history_strings") as Array[String]) == recent_before, "Back leaves dirty state and recents unchanged")
|
||||
_expect(selector.visible and title.text == "Choose background color", "Back returns to color choices with the scene picker still open")
|
||||
|
||||
await _activate_button(controls.get("_current_chip") as Button)
|
||||
picker_view = selector.get("_color_picker_view") as StageSurfaceColorPickerView
|
||||
picker = picker_view.find_child("ColorPickerControl", true, false) as ColorPicker if picker_view != null else null
|
||||
_set_picker_draft(picker_view, picker, Color("#26A8D6"))
|
||||
await _press_escape()
|
||||
_expect(not bool(_stage.get("_plain_color_draft_active")) and plain_fill.color.to_html(false).to_upper() == confirmed_hex.trim_prefix("#"), "Escape from the custom picker restores the prior fill")
|
||||
_expect(selector.visible and title.text == "Choose background color", "Escape returns to color choices instead of closing the Stage chooser")
|
||||
|
||||
await _activate_button(controls.get("_current_chip") as Button)
|
||||
picker_view = selector.get("_color_picker_view") as StageSurfaceColorPickerView
|
||||
picker = picker_view.find_child("ColorPickerControl", true, false) as ColorPicker if picker_view != null else null
|
||||
_set_picker_draft(picker_view, picker, draft_color)
|
||||
await _activate_button(selector.get("_color_use_button") as Button)
|
||||
var committed_hex: String = _stage.call("_canonical_surface_color", _stage.get("_plain_color")) as String
|
||||
var recent_after_commit: Array[String] = _stage.call("_surface_color_history_strings") as Array[String]
|
||||
_expect(committed_hex == "#B34FD8" and plain_fill.color.to_html(false).to_upper() == "B34FD8", "Use color confirms the custom color on the Stage")
|
||||
_expect(bool(_stage.get("_dirty")) and recent_after_commit.count(committed_hex) == 1 and recent_after_commit[0] == committed_hex, "one confirmation marks changed scene dirty and records the color once")
|
||||
_expect(selector.visible and title.text == "Choose background color", "Use color returns to the choices view")
|
||||
|
||||
var path: String = "user://phase19_plain_background_roundtrip.scene"
|
||||
var saved: bool = _stage.call("_save_scene_to_path", path, false) as bool
|
||||
var read: Dictionary = STAGE_SCENE_IO.read_file(path)
|
||||
var saved_data: Dictionary = read.get("data", {}) as Dictionary
|
||||
_expect(saved and bool(read.get("ok", false)) and String(saved_data.get("background_kind", "")) == "plain" and String(saved_data.get("plain_color", "")) == committed_hex, "production save/reopen boundary stores the confirmed Plain color")
|
||||
_stage.call("_close_selector")
|
||||
_stage.call("_open_selector", "scenery")
|
||||
selector = browser.get_selector()
|
||||
selector.call("_set_gallery_tab", "backgrounds")
|
||||
await process_frame
|
||||
grid = selector.find_child("GridContainer", true, false) as GridContainer
|
||||
var sky_card: AssetCard = _find_card(grid, "sky_clear_day")
|
||||
if sky_card != null:
|
||||
await _activate_card(sky_card)
|
||||
_expect(String(_stage.get("_background_kind")) == "sky" and _stage.call("_canonical_surface_color", _stage.get("_plain_color")) == committed_hex, "switching to Sky retains the remembered Plain color")
|
||||
var sky_saved: Dictionary = _stage.call("_collect_scene_data", false) as Dictionary
|
||||
_expect(String(sky_saved.get("background_kind", "")) == "sky" and String(sky_saved.get("plain_color", "")) == committed_hex, "Sky-active scene snapshot preserves the remembered Plain color")
|
||||
grid = selector.find_child("GridContainer", true, false) as GridContainer
|
||||
var return_plain_card: AssetCard = _find_card(grid, "plain_background")
|
||||
if return_plain_card != null:
|
||||
await _activate_card(return_plain_card)
|
||||
_expect(String(_stage.get("_background_kind")) == "plain" and _stage.call("_canonical_surface_color", _stage.get("_plain_color")) == committed_hex, "returning from Sky restores the confirmed Plain color")
|
||||
controls = selector.find_child("PlainBackgroundColorControls", true, false) as StageSurfaceColorControls
|
||||
var preset_swatches: ColorSwatchSelector = controls.get("_preset_swatches") as ColorSwatchSelector if controls != null else null
|
||||
var preset_button: Button = preset_swatches.get_child(0) as Button if preset_swatches != null and preset_swatches.get_child_count() > 0 else null
|
||||
var preset_color: Color = Color.WHITE
|
||||
if preset_button != null:
|
||||
preset_color = preset_button.get_meta("surface_color", Color.WHITE)
|
||||
if preset_button != null:
|
||||
await _activate_button(preset_button)
|
||||
var preset_hex: String = _stage.call("_canonical_surface_color", preset_color) as String
|
||||
var preset_recents: Array[String] = _stage.call("_surface_color_history_strings") as Array[String]
|
||||
_expect(preset_button != null and preset_button.button_pressed and preset_button.text == "✓", "preset swatch selection displays its selected check")
|
||||
_expect(_stage.call("_canonical_surface_color", _stage.get("_plain_color")) == preset_hex and preset_recents[0] == preset_hex, "preset swatch immediately confirms the Stage color and moves it to recent colors")
|
||||
await _save_visual_capture("phase19_plain_preset_selected.png")
|
||||
_stage.call("_close_selector")
|
||||
var loaded: bool = _stage.call("_load_scene_from_path", path, false) as bool
|
||||
_expect(loaded and String(_stage.get("_background_kind")) == "plain" and _stage.call("_canonical_surface_color", _stage.get("_plain_color")) == committed_hex, "production Stage load restores the confirmed Plain background")
|
||||
if FileAccess.file_exists(path):
|
||||
DirAccess.remove_absolute(ProjectSettings.globalize_path(path))
|
||||
|
||||
|
||||
func _test_draft_cancel_on_mode_switch() -> void:
|
||||
var browser: StageAssetBrowser = _stage.get("_asset_browser") as StageAssetBrowser
|
||||
_stage.call("_open_selector", "scenery")
|
||||
var selector: AssetSelector = browser.get_selector()
|
||||
selector.call("_set_gallery_tab", "backgrounds")
|
||||
await process_frame
|
||||
var grid: GridContainer = selector.find_child("GridContainer", true, false) as GridContainer
|
||||
var plain_card: AssetCard = _find_card(grid, "plain_background")
|
||||
if plain_card != null:
|
||||
await _activate_card(plain_card)
|
||||
var controls: StageSurfaceColorControls = selector.find_child("PlainBackgroundColorControls", true, false) as StageSurfaceColorControls
|
||||
await _activate_button(controls.get("_current_chip") as Button)
|
||||
var picker_view: StageSurfaceColorPickerView = selector.get("_color_picker_view") as StageSurfaceColorPickerView
|
||||
var picker: ColorPicker = picker_view.find_child("ColorPickerControl", true, false) as ColorPicker if picker_view != null else null
|
||||
_set_picker_draft(picker_view, picker, Color("#E66A21"))
|
||||
await process_frame
|
||||
var confirmed_hex: String = _stage.call("_canonical_surface_color", _stage.get("_plain_color")) as String
|
||||
_stage.call("set_mode", SandboxStage.StageMode.DIRECT)
|
||||
await process_frame
|
||||
var background: StageBackgroundView = _stage.get("_background_view") as StageBackgroundView
|
||||
var fill: ColorRect = background.get_node("PlainFill") as ColorRect
|
||||
_expect(not bool(_stage.get("_plain_color_draft_active")) and not selector.visible, "mode switch closes an active custom picker and cancels its draft")
|
||||
_expect(fill.color.to_html(false).to_upper() == confirmed_hex.trim_prefix("#"), "mode-switch cancel restores the confirmed backdrop")
|
||||
_stage.call("set_mode", SandboxStage.StageMode.EDIT)
|
||||
await process_frame
|
||||
|
||||
|
||||
func _test_draft_cancel_on_popup_hide() -> void:
|
||||
var browser: StageAssetBrowser = _stage.get("_asset_browser") as StageAssetBrowser
|
||||
_stage.call("_open_selector", "scenery")
|
||||
var selector: AssetSelector = browser.get_selector()
|
||||
selector.call("_set_gallery_tab", "backgrounds")
|
||||
await process_frame
|
||||
var grid: GridContainer = selector.find_child("GridContainer", true, false) as GridContainer
|
||||
var plain_card: AssetCard = _find_card(grid, "plain_background")
|
||||
if plain_card != null:
|
||||
await _activate_card(plain_card)
|
||||
var controls: StageSurfaceColorControls = selector.find_child("PlainBackgroundColorControls", true, false) as StageSurfaceColorControls
|
||||
await _activate_button(controls.get("_current_chip") as Button)
|
||||
var picker_view: StageSurfaceColorPickerView = selector.get("_color_picker_view") as StageSurfaceColorPickerView
|
||||
var picker: ColorPicker = picker_view.find_child("ColorPickerControl", true, false) as ColorPicker if picker_view != null else null
|
||||
_set_picker_draft(picker_view, picker, Color("#AC5E31"))
|
||||
var confirmed_hex: String = _stage.call("_canonical_surface_color", _stage.get("_plain_color")) as String
|
||||
selector.hide()
|
||||
await process_frame
|
||||
await process_frame
|
||||
var background: StageBackgroundView = _stage.get("_background_view") as StageBackgroundView
|
||||
var fill: ColorRect = background.get_node("PlainFill") as ColorRect
|
||||
_expect(not bool(_stage.get("_plain_color_draft_active")), "unexpected popup dismissal cancels the custom-color draft")
|
||||
_expect(fill.color.to_html(false).to_upper() == confirmed_hex.trim_prefix("#") and selector.visible, "popup dismissal restores the confirmed fill and keeps the chooser available")
|
||||
browser.close()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _test_draft_cancel_on_scene_replacement(starter_data: Dictionary) -> void:
|
||||
var browser: StageAssetBrowser = _stage.get("_asset_browser") as StageAssetBrowser
|
||||
_stage.call("_open_selector", "scenery")
|
||||
var selector: AssetSelector = browser.get_selector()
|
||||
selector.call("_set_gallery_tab", "backgrounds")
|
||||
await process_frame
|
||||
var grid: GridContainer = selector.find_child("GridContainer", true, false) as GridContainer
|
||||
var plain_card: AssetCard = _find_card(grid, "plain_background")
|
||||
if plain_card != null:
|
||||
await _activate_card(plain_card)
|
||||
var controls: StageSurfaceColorControls = selector.find_child("PlainBackgroundColorControls", true, false) as StageSurfaceColorControls
|
||||
await _activate_button(controls.get("_current_chip") as Button)
|
||||
var picker_view: StageSurfaceColorPickerView = selector.get("_color_picker_view") as StageSurfaceColorPickerView
|
||||
var picker: ColorPicker = picker_view.find_child("ColorPickerControl", true, false) as ColorPicker if picker_view != null else null
|
||||
_set_picker_draft(picker_view, picker, Color("#46A45F"))
|
||||
await process_frame
|
||||
var replaced: bool = _stage.call("_apply_scene_data", starter_data, "", false) as bool
|
||||
var background: StageBackgroundView = _stage.get("_background_view") as StageBackgroundView
|
||||
var fill: ColorRect = background.get_node("PlainFill") as ColorRect
|
||||
_expect(replaced and not bool(_stage.get("_plain_color_draft_active")), "scene replacement applies after canceling the custom-color draft")
|
||||
_expect(not selector.visible and String(_stage.get("_background_kind")) == "plain", "scene replacement closes the old selector and uses the new Plain starter")
|
||||
_expect(fill.color.to_html(false).to_upper() == "F5EFE0", "replacement renders the new scene's confirmed starter color")
|
||||
await _save_visual_capture("phase19_plain_offwhite_stage.png")
|
||||
_stage.call("_commit_plain_color", Color("#262B36"))
|
||||
await _save_visual_capture("phase19_plain_dark_stage.png")
|
||||
_stage.call("set_mode", SandboxStage.StageMode.DIRECT)
|
||||
await process_frame
|
||||
await _save_visual_capture("phase19_plain_direct_mode.png")
|
||||
_stage.call("set_mode", SandboxStage.StageMode.PLAY)
|
||||
await process_frame
|
||||
await _save_visual_capture("phase19_plain_play_mode.png")
|
||||
var camera: Camera2D = _stage.get("_camera") as Camera2D
|
||||
_stage.call("set_mode", SandboxStage.StageMode.EDIT)
|
||||
_stage.set("_cli_startup", true)
|
||||
var hovered_control: Control = root.gui_get_hovered_control()
|
||||
var saved_mouse_filter: Control.MouseFilter = hovered_control.mouse_filter if hovered_control != null else Control.MOUSE_FILTER_STOP
|
||||
if hovered_control != null:
|
||||
hovered_control.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
await process_frame
|
||||
camera.global_position = Vector2(0.0, -400.0)
|
||||
camera.zoom = Vector2.ONE * 0.5
|
||||
var wheel: InputEventMouseButton = InputEventMouseButton.new()
|
||||
wheel.button_index = MOUSE_BUTTON_WHEEL_UP
|
||||
wheel.pressed = true
|
||||
wheel.position = Vector2(root.size) * 0.5
|
||||
_stage.call("_input", wheel)
|
||||
var pan_press: InputEventMouseButton = InputEventMouseButton.new()
|
||||
pan_press.button_index = MOUSE_BUTTON_MIDDLE
|
||||
pan_press.pressed = true
|
||||
pan_press.position = wheel.position
|
||||
_stage.call("_input", pan_press)
|
||||
var pan_motion: InputEventMouseMotion = InputEventMouseMotion.new()
|
||||
pan_motion.position = pan_press.position + Vector2(80.0, -30.0)
|
||||
pan_motion.relative = Vector2(80.0, -30.0)
|
||||
_stage.call("_input", pan_motion)
|
||||
var pan_release: InputEventMouseButton = InputEventMouseButton.new()
|
||||
pan_release.button_index = MOUSE_BUTTON_MIDDLE
|
||||
pan_release.position = pan_motion.position
|
||||
_stage.call("_input", pan_release)
|
||||
await process_frame
|
||||
_expect(camera.zoom.x > 0.5 and not camera.global_position.is_equal_approx(Vector2(0.0, -400.0)), "plain backdrop remains visible through production zoom and pan input")
|
||||
_stage.set("_cli_startup", false)
|
||||
if hovered_control != null and is_instance_valid(hovered_control):
|
||||
hovered_control.mouse_filter = saved_mouse_filter
|
||||
await _save_visual_capture("phase19_plain_dark_pan_zoom.png")
|
||||
root.size = Vector2i(640, 480)
|
||||
await process_frame
|
||||
await process_frame
|
||||
await _save_visual_capture("phase19_plain_dark_narrow_viewport.png")
|
||||
browser = _stage.get("_asset_browser") as StageAssetBrowser
|
||||
_stage.call("_open_selector", "scenery")
|
||||
selector = browser.get_selector()
|
||||
selector.call("_set_gallery_tab", "backgrounds")
|
||||
await process_frame
|
||||
grid = selector.find_child("GridContainer", true, false) as GridContainer
|
||||
plain_card = _find_card(grid, "plain_background")
|
||||
if plain_card != null:
|
||||
await _activate_card(plain_card)
|
||||
await process_frame
|
||||
var selector_rect: Rect2 = Rect2(Vector2(selector.position), Vector2(selector.size))
|
||||
var narrow_size: Vector2 = Vector2(root.size)
|
||||
_expect(selector.visible and selector_rect.position.x >= 0.0 and selector_rect.position.y >= 0.0 and selector_rect.end.x <= narrow_size.x and selector_rect.end.y <= narrow_size.y, "Plain color choices stay inside a narrow viewport")
|
||||
await _save_visual_capture("phase19_plain_narrow_choices.png")
|
||||
browser.close()
|
||||
root.size = Vector2i(1280, 720)
|
||||
await process_frame
|
||||
|
||||
|
||||
func _test_recent_color_history_limit() -> void:
|
||||
for index: int in range(9):
|
||||
_stage.call("_record_recent_surface_color", Color.from_hsv(float(index) / 9.0, 0.8, 0.9))
|
||||
var recent: Array[String] = _stage.call("_surface_color_history_strings") as Array[String]
|
||||
_expect(recent.size() == 8, "recent surface color history is capped at eight colors")
|
||||
var newest: String = _stage.call("_canonical_surface_color", Color.from_hsv(8.0 / 9.0, 0.8, 0.9)) as String
|
||||
_expect(not recent.is_empty() and recent[0] == newest, "recent surface color history is most-recent-first")
|
||||
|
||||
|
||||
func _valid_document() -> Dictionary:
|
||||
return {
|
||||
"version": "1.7",
|
||||
"scene_name": "Validation fixture",
|
||||
"sky_id": "sky_neutral",
|
||||
"background_kind": "plain",
|
||||
"plain_color": "#F5EFE0",
|
||||
"camera": {"position": {"x": 0.0, "y": -400.0}, "zoom": 0.5},
|
||||
"objects": [],
|
||||
"event_rules": [],
|
||||
}
|
||||
|
||||
|
||||
func _find_card(grid: GridContainer, entry_id: String) -> AssetCard:
|
||||
if grid == null:
|
||||
return null
|
||||
for child: Node in grid.get_children():
|
||||
var card: AssetCard = child as AssetCard
|
||||
if card != null and String(card.get_meta("entry_id", "")) == entry_id:
|
||||
return card
|
||||
return null
|
||||
|
||||
|
||||
func _activate_card(card: AssetCard) -> void:
|
||||
card.activated.emit(card.payload())
|
||||
await process_frame
|
||||
|
||||
|
||||
func _activate_button(button: Button) -> void:
|
||||
if button == null:
|
||||
_expect(false, "expected production button exists")
|
||||
return
|
||||
button.pressed.emit()
|
||||
await process_frame
|
||||
|
||||
|
||||
func _press_escape() -> void:
|
||||
var viewport: Viewport = root
|
||||
var press := InputEventKey.new()
|
||||
press.keycode = KEY_ESCAPE
|
||||
press.pressed = true
|
||||
viewport.push_input(press)
|
||||
await process_frame
|
||||
var release := InputEventKey.new()
|
||||
release.keycode = KEY_ESCAPE
|
||||
release.pressed = false
|
||||
viewport.push_input(release)
|
||||
await process_frame
|
||||
|
||||
|
||||
func _set_picker_draft(view: StageSurfaceColorPickerView, picker: ColorPicker, color: Color) -> void:
|
||||
picker.color = color
|
||||
view.call("_on_picker_color_changed", color)
|
||||
await process_frame
|
||||
|
||||
|
||||
func _save_visual_capture(file_name: String) -> void:
|
||||
if DisplayServer.get_name() == "headless":
|
||||
return
|
||||
await RenderingServer.frame_post_draw
|
||||
var capture: Image = root.get_texture().get_image()
|
||||
var capture_dir: String = ProjectSettings.globalize_path("res://.phase19_captures")
|
||||
DirAccess.make_dir_recursive_absolute(capture_dir)
|
||||
var error: Error = capture.save_png(capture_dir.path_join(file_name))
|
||||
_expect(error == OK, "rendered capture saved: %s" % file_name)
|
||||
Reference in New Issue
Block a user