# help_ui_test —— §8.3 帮助窗 headless 自检(真 `helpwindow.py` uiscript + 假 client)。 # godot --headless --path project --script help_ui_test.gd # 校验:helpwindow.py 装载、19 条帮助行 + 任务栏标签逐字绑定(对齐 # `locale/locale/en/locale_interface.txt` 的 `HELP_*`)、close_button、open/close/toggle、 # 以及 SystemMenuUI.open_help() 懒建并打开本窗。缺 uiscript 资产时优雅跳过。 extends SceneTree const UiManager = preload("res://ui/ui_manager.gd") const HelpUI = preload("res://ui/help_ui.gd") const SystemMenuUI = preload("res://ui/system_menu_ui.gd") class FakeClient extends Node: func say(_type: int, _text: String) -> bool: return true var _fail := 0 func _ck(c: bool, m: String) -> void: if not c: _fail += 1 printerr("FAIL: " + m) func _init() -> void: _run() if _fail == 0: print("PASS: help_ui_test (helpwindow.py + HELP_* rows + close/open/toggle + SystemMenu.open_help)") quit(0) else: printerr("%d check(s) failed" % _fail) quit(1) func _txt(hw: Node, nm: String) -> String: var n: Control = hw._node(nm) return String(n.text) if n and ("text" in n) else "" % nm func _run() -> void: var assets := AssetRoot.path() if not FileAccess.file_exists(assets.path_join("uiscript/uiscript/helpwindow.py")): print(" (skip: no helpwindow.py — assets checkout missing)") return var ui: CanvasLayer = UiManager.new() get_root().add_child(ui) ui._ready() var fc := FakeClient.new() get_root().add_child(fc) var hw: Node = HelpUI.new() get_root().add_child(hw) hw.setup(ui, fc, assets) hw.open() _ck(hw.is_open(), "help window opened") if not hw.is_open(): return # --- 19 条浮动帮助行都绑定且非占位 --- var bound := 0 for i in range(1, 20): var nm := "help_%02d" % i var s := _txt(hw, nm) _ck(not s.begins_with("")), "%s not a placeholder (got %s)" % [nm, s]) if not s.strip_edges().is_empty() and not (s.begins_with("<") and s.ends_with(">")): bound += 1 _ck(bound == 19, "all 19 help rows bound (got %d)" % bound) # --- 逐字对照 locale/locale/en/locale_interface.txt --- _ck(_txt(hw, "help_01") == "Panel: W, A, S, D or arrow keys", "help_01 = HELP_MOVE_KEY (got %s)" % _txt(hw, "help_01")) _ck(_txt(hw, "help_06") == "Attack: left mouse button or space bar", "help_06 = HELP_ATTACK_KEY (got %s)" % _txt(hw, "help_06")) _ck(_txt(hw, "help_02") == "Camera View: middle or right mouse button", "help_02 = HELP_CONTROL_CAMERA_BY_MIDDLEBUTTON (2nd dup wins) (got %s)" % _txt(hw, "help_02")) _ck(_txt(hw, "help_19") == "Display help: H", "help_19 = HELP_HELP (got %s)" % _txt(hw, "help_19")) # --- 任务栏贴纸标签 --- _ck(_txt(hw, "taskbar_help_02") == "Hit Points (HP)", "taskbar_help_02 = HELP_HP (got %s)" % _txt(hw, "taskbar_help_02")) _ck(_txt(hw, "taskbar_help_08b") == "(Character Window, Inventory Window,", "taskbar_help_08b = HELP_CHARACTER_BUTTON1 (got %s)" % _txt(hw, "taskbar_help_08b")) # --- close_button --- var close_btn: Control = hw._node("close_button") _ck(close_btn is BaseButton, "close_button is a button") _ck(_txt(hw, "close_button") == "Close", "close_button text = Close (got %s)" % _txt(hw, "close_button")) # --- rows() 便捷器 --- var rows: Array = hw.rows() _ck(rows.size() == 19, "rows() returns 19 entries (got %d)" % rows.size()) var all_nonempty := true for r in rows: if String(r).strip_edges().is_empty(): all_nonempty = false _ck(all_nonempty, "rows() all non-empty") # --- close_button 关窗 --- close_btn.pressed.emit() _ck(not hw.is_open(), "close_button closes help window") # --- open / toggle / ESC 栈 --- hw.toggle() _ck(hw.is_open(), "toggle() re-opens help window") _ck(ui.top() == hw._win.get("root"), "help window is top of UiManager stack (ESC closes it)") hw.toggle() _ck(not hw.is_open(), "toggle() closes help window") # --- SystemMenuUI.open_help() 懒建并打开 --- var sm: Node = SystemMenuUI.new() get_root().add_child(sm) sm.setup(ui, fc, assets) sm.open_help() _ck(is_instance_valid(sm.help_ui), "SystemMenuUI.open_help() lazily builds help_ui") _ck(sm.help_ui.is_open(), "SystemMenuUI.open_help() opens the help window") sm.help_ui.close()