feat(shell): SystemDock slide-in with inert screen-routing seam
This commit is contained in:
6
client/scenes/shell/SystemDock.tscn
Normal file
6
client/scenes/shell/SystemDock.tscn
Normal file
@@ -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")
|
||||
68
client/scripts/ui/shell/system_dock.gd
Normal file
68
client/scripts/ui/shell/system_dock.gd
Normal file
@@ -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)
|
||||
1
client/scripts/ui/shell/system_dock.gd.uid
Normal file
1
client/scripts/ui/shell/system_dock.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dvbg24rvye3qw
|
||||
32
client/tests/unit/test_system_dock.gd
Normal file
32
client/tests/unit/test_system_dock.gd
Normal file
@@ -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")
|
||||
1
client/tests/unit/test_system_dock.gd.uid
Normal file
1
client/tests/unit/test_system_dock.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dllvm2kmia00h
|
||||
Reference in New Issue
Block a user