diff --git a/client/scenes/shell/SystemDock.tscn b/client/scenes/shell/SystemDock.tscn new file mode 100644 index 0000000..f984bdc --- /dev/null +++ b/client/scenes/shell/SystemDock.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3] + +[ext_resource type="Script" path="res://scripts/ui/shell/system_dock.gd" id="1"] + +[node name="SystemDock" type="Control"] +script = ExtResource("1") diff --git a/client/scripts/ui/shell/system_dock.gd b/client/scripts/ui/shell/system_dock.gd new file mode 100644 index 0000000..16df17a --- /dev/null +++ b/client/scripts/ui/shell/system_dock.gd @@ -0,0 +1,68 @@ +class_name SystemDock +extends Control +## The slide-in system dock (mock 2a): a gold handle toggles a column of screen +## buttons in/out. §2: state (owns the open toggle via ShellState). The buttons +## are the routing seam — they emit screen_requested; the screens they open land +## in later milestones, so the signal is currently a no-op for the shell. + +signal screen_requested(id: StringName) + +const SCREENS := [ + [&"inventory", "Inventory", "I"], + [&"character", "Character", "C"], + [&"quest_log", "Quest Log", "J"], + [&"spellbook", "Spellbook", "K"], + [&"world_map", "World Map", "M"], + [&"party", "Party", "P"], +] +const SLIDE_SECONDS := 0.32 +const HIDDEN_SHIFT := 230.0 + +var _screen_buttons: Dictionary = {} +var _state: ShellState +var _menu: VBoxContainer +var _handle: Button + + +func _ready() -> void: + _menu = VBoxContainer.new() + _menu.add_theme_constant_override("separation", 10) + add_child(_menu) + for entry in SCREENS: + var id: StringName = entry[0] + var button := Button.new() + button.text = "%s %s" % [entry[2], entry[1]] + button.theme_type_variation = ThemeKeys.DARK_PANEL + button.pressed.connect(func(): screen_requested.emit(id)) + _menu.add_child(button) + _screen_buttons[id] = button + + _handle = Button.new() + _handle.text = "›" + _handle.theme_type_variation = ThemeKeys.TAB_ACTIVE + _handle.pressed.connect(_on_handle_pressed) + add_child(_handle) + + +func setup(state: ShellState) -> void: + _state = state + _apply_open(_state.dock_open) + + +func _on_handle_pressed() -> void: + if _state == null: + return + _apply_open(_state.toggle_dock()) + + +func _apply_open(open: bool) -> void: + _handle.text = "›" if open else "‹" + var target := Vector2.ZERO if open else Vector2(HIDDEN_SHIFT, 0.0) + var alpha := 1.0 if open else 0.0 + if not is_inside_tree(): + _menu.position = target + _menu.modulate.a = alpha + return + var tween := create_tween().set_parallel(true) + tween.tween_property(_menu, "position", target, SLIDE_SECONDS) + tween.tween_property(_menu, "modulate:a", alpha, SLIDE_SECONDS) diff --git a/client/scripts/ui/shell/system_dock.gd.uid b/client/scripts/ui/shell/system_dock.gd.uid new file mode 100644 index 0000000..a2b81dc --- /dev/null +++ b/client/scripts/ui/shell/system_dock.gd.uid @@ -0,0 +1 @@ +uid://dvbg24rvye3qw diff --git a/client/tests/unit/test_system_dock.gd b/client/tests/unit/test_system_dock.gd new file mode 100644 index 0000000..233a9c6 --- /dev/null +++ b/client/tests/unit/test_system_dock.gd @@ -0,0 +1,32 @@ +extends "res://addons/gut/test.gd" + +const SCENE := "res://scenes/shell/SystemDock.tscn" + + +func _dock() -> SystemDock: + var d = load(SCENE).instantiate() + add_child_autofree(d) # _ready() builds the buttons + return d + + +func test_builds_all_six_screen_buttons(): + var d := _dock() + assert_eq(d._screen_buttons.size(), 6) + assert_true(d._screen_buttons.has(&"spellbook"), "spellbook kept for mock fidelity") + assert_true(d._screen_buttons.has(&"party")) + + +func test_pressing_a_button_emits_its_id(): + var d := _dock() + watch_signals(d) + d._screen_buttons[&"inventory"].emit_signal("pressed") + assert_signal_emitted_with_parameters(d, "screen_requested", [&"inventory"]) + + +func test_handle_toggles_state(): + var d := _dock() + var state := ShellState.seed() + d.setup(state) + assert_true(state.dock_open) + d._on_handle_pressed() + assert_false(state.dock_open, "handle flips the shared state") diff --git a/client/tests/unit/test_system_dock.gd.uid b/client/tests/unit/test_system_dock.gd.uid new file mode 100644 index 0000000..5629317 --- /dev/null +++ b/client/tests/unit/test_system_dock.gd.uid @@ -0,0 +1 @@ +uid://dllvm2kmia00h