Randoloot/tests/ships/floating_windows_test.gd
2026-10-16 22:18:07 +02:00

123 lines
5.6 KiB
GDScript

extends Node
const GAME := preload("res://scenes/game/game.tscn")
func motion(point: Vector2, relative: Vector2 = Vector2.ZERO) -> void:
var event := InputEventMouseMotion.new()
event.position = point
event.global_position = point
event.relative = relative
event.button_mask = MOUSE_BUTTON_MASK_LEFT if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) else 0
get_viewport().push_input(event, true)
func mouse(point: Vector2, pressed: bool) -> void:
var event := InputEventMouseButton.new()
event.position = point
event.global_position = point
event.button_index = MOUSE_BUTTON_LEFT
event.pressed = pressed
event.button_mask = MOUSE_BUTTON_MASK_LEFT if pressed else 0
get_viewport().push_input(event, true)
func click(point: Vector2) -> void:
motion(point)
mouse(point, true)
mouse(point, false)
func drag(header: Control, displacement: Vector2) -> void:
var origin := header.get_global_rect().position + Vector2(15, header.get_global_rect().size.y * 0.5)
motion(origin)
mouse(origin, true)
motion(origin + displacement, displacement)
mouse(origin + displacement, false)
func _ready() -> void:
process_mode = Node.PROCESS_MODE_ALWAYS
GameState.start_new_run()
var game := GAME.instantiate() as Node2D
add_child(game)
await get_tree().process_frame
await get_tree().process_frame
game.set_physics_process(false)
var ship := game.get_node("PlayerShip") as CharacterBody2D
ship.set_physics_process(false)
ship.get_node("WeaponController").set_physics_process(false)
for enemy in get_tree().get_nodes_in_group("enemies"):
enemy.set_physics_process(false)
var hud := game.get_node("HUD")
var manager := hud.get_node("HUDRoot/FloatingWindows")
var craft: PanelContainer = hud.get("_crafting_window")
var inventory: Control = hud.get("inventory_panel")
var drawer: Control = hud.get("_inventory_clip")
var sidebar: Control = hud.get("_sidebar")
hud.call("_toggle_inventory")
craft.show()
await get_tree().process_frame
await get_tree().process_frame
# Put inventory directly behind crafting. Its salvage button occupies the same pixel.
drawer.set_meta("floating_window_dragged", true)
var recipe: Button = craft.get_node("Contents/CraftingPanel").get("_recipe_buttons")["parts"]
var point := recipe.get_global_rect().get_center()
var first_slot := inventory.get_node("Contents/CargoGrid").get_child(0) as Control
drawer.global_position += point - first_slot.get_global_rect().get_center()
manager.call("focus_window", drawer)
manager.call("focus_window", craft)
var stock := ship.get_node("ShipInventory") as ShipInventory
var item := ItemInstance.new()
item.definition = preload("res://resources/items/plasma_cannon.tres")
assert(stock.add_item(item))
GameState.captain.minerals.merge({"iron": 2, "titanium": 2, "aluminium": 2}, true)
GameState.captain.emit_changed()
await get_tree().process_frame
assert(manager.call("window_at", point) == craft)
click(point)
assert(GameState.captain.parts == 1.0, "Top crafting button must receive the click")
assert(stock.cargo[0] == item, "Underlying inventory must not consume the click")
assert(craft.z_index > drawer.z_index)
assert(craft.get_index() > drawer.get_index())
# Dragging a title moves its window; content clicks do not start a window drag.
var before := craft.global_position
drag(craft.get_node("Contents/Header"), Vector2(-80, -60))
assert(craft.global_position.is_equal_approx(before + Vector2(-80, -60)))
await get_tree().process_frame
assert(craft.global_position.is_equal_approx(before + Vector2(-80, -60)))
# The exposed inventory header can activate and raise the lower window.
drawer.global_position = Vector2(70, 80)
manager.call("focus_window", craft)
var inv_header := inventory.get_node("Contents/Header") as Control
click(inv_header.get_global_rect().position + Vector2(10, 8))
assert(drawer.z_index > craft.z_index and drawer.get_index() > craft.get_index())
before = drawer.global_position
drag(inv_header, Vector2(100, 80))
assert(drawer.global_position.is_equal_approx(before + Vector2(100, 80)))
hud.call("_layout_inventory")
assert(drawer.global_position.is_equal_approx(before + Vector2(100, 80)))
# Close buttons do not turn into drag handles; reopening preserves the moved position.
click(inventory.get_node("Contents/Header/CloseButton").get_global_rect().get_center())
assert(not inventory.visible)
inventory.call("_set_drawer_open", true)
assert(drawer.global_position.is_equal_approx(before + Vector2(100, 80)))
# Sidebar dragging survives equipment relayout and viewport clamping.
manager.call("focus_window", sidebar)
before = sidebar.global_position
drag(sidebar.get_node("Scroll/Contents/ShipEquipmentPanel/Contents/Title"), Vector2(-100, -50))
hud.call("_layout_sidebar")
assert(sidebar.global_position.is_equal_approx(before + Vector2(-100, -50)))
# The captain modal remains draggable while paused and blocks windows below it.
var skills: CanvasLayer = hud.get("_captain_skills_ui")
skills.call("open_management")
await get_tree().process_frame
await get_tree().process_frame
assert(get_tree().paused)
var panel: Control = skills.get("_panel")
before = panel.global_position
drag((skills.get("_contents") as Control).get_node("Header"), Vector2(50, 30))
assert(panel.global_position.is_equal_approx(before + Vector2(50, 30)))
skills.call("_layout")
assert(panel.global_position.is_equal_approx(before + Vector2(50, 30)))
skills.call("_close")
assert(not get_tree().paused)
assert(not ship.get_node("WeaponController").get("_fire_buttons_down")[0])
print("FLOATING_WINDOWS_TEST: PASS (real GUI click routing over inventory, matching z/tree order, title drag, focus/raise, close/reopen, relayout persistence, paused captain modal, gameplay input blocked)")
get_tree().quit()