Files
gplan-2/game/presentation/ui_registry.gd
T
DKChan 4e4232d804 卡⑤T1-T3(迭代47·Esc浮窗与营地顶栏批): Esc浮窗三钮+MainEscFlow四态路由+CampHudBand顶栏栏+设置语境分支+断言批——终态六枚落满
- 三新件: camp_esc_overlay(modal_shell+三钮,退出=danger_button,零动效零新素材)/main_esc_flow(静态承接件零成员态:is_camp_context+on_esc_input四态路由+_other_modal_open登记册集合查询+三出口动线)/camp_hud_band(48px浮层+keystone_badge,refresh_camp=bus目标册契约面)
- 接线: ui_registry contract+node()第六槽(营地层与设置层之间——契约3栈语义正解);ui_camp_modals六枚落满(卡⑥终态);main_ui_build实例化+三出口薄委托接线+bus目标册纳入HUD栏;main.gd _unhandled_input(契约9接线定稿:KEY_ESCAPE配physical/pressed非echo/禁轮询/不挂ui_cancel)+三薄委托零新增成员;presenter.open_camp尾挂刷新单口(契约5时机②);main_overlay_flow._on_settings_closed语境分支(谓词=esc_overlay.visible谁开谁收)
- 契约9分支序修正: ①先于②(设置开在浮窗之上态先命中无反馈——浮窗不隔层关闭;首装②先被实机场景证伪,孤检2红溯源后按卡面编号归位)
- 断言批: screen_flow Esc步十断言(根态唤起/再按关窗/echo零响应/子界面无反馈/HUD直写显式触发9999/设置开态不误关/关设置回浮窗/返回动线四可见性/菜单语境不唤起)+ui_struct浮窗段(三钮仅三/零动效双件源码+子树AnimPlayer=0/debug_badge零波及)
- 验证: 冒烟PASS+system_test 69项0失败+七探针全绿(screen_flow/ui_struct含Esc段/ui_click问题=0/ui_probe/ui_contrast36对/shot);S9/S10/S13归基线
2026-11-01 18:50:00 +08:00

112 lines
5.6 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 界面注册面:呈现层界面元素清单的唯一事实源——哪些层、什么序、地址在哪。
## 持有三域容器(screens/battle/modals)、LAYER_CONTRACT 合同表、node(key) 合同寻址、
## apply_layer_contract(root) 唯一落位口(全仓唯一 move_child 点)。
## RefCounted 不挂树:零信号连接、零会话期引用、零核心写调用——组合根单点装配不变。
class_name UiRegistry
extends RefCounted
const ModalStack := preload("res://presentation/modal_stack.gd")
# ==================== 视觉层合同(唯一事实源——树序=登记序=z 序;改序只改此表) ====================
# kind: shell=屏壳容器(成员随壳不占独立树位;level_screen 例外另占登记位)/modal=模态层(入登记册,
# tags 随登记)/state=全屏态(占树位不入登记册)/node=非视觉节点(占树位不入登记册)。
# host=宿住屏壳(树序随宿主、登记序按本合同);shell=模态成员的屏壳(成员与屏壳同槽:屏壳占该树位、
# 成员占该登记位)。落位=apply_layer_contract(全仓唯一层序落位点,add_child 之后统一排序+登记)。
const LAYER_CONTRACT: Array[Dictionary] = [
{"key": "adventure_screen", "kind": "shell"},
{"key": "menu_screen", "kind": "shell"},
{"key": "row_pacer", "kind": "node"},
{"key": "legend_overlay", "kind": "modal", "tags": []},
{"key": "node_overlay", "kind": "modal", "tags": []},
{"key": "level_screen", "kind": "modal", "tags": [ModalStack.TAG_SCREEN_STATE], "host": "adventure_screen"},
{"key": "curio_overlay", "kind": "modal", "tags": []},
{"key": "end_overlay", "kind": "modal", "tags": []},
{"key": "shop_overlay", "kind": "modal", "tags": []},
{"key": "camp_scene", "kind": "modal", "tags": [], "shell": "camp_screen"}, # 营地场景根(交互式场景图——卡④)
{"key": "forge_view", "kind": "modal", "tags": []}, # 营地四子界面(独立全屏页——场景根留底形态,卡④ T3)
{"key": "treasure_view", "kind": "modal", "tags": []},
{"key": "tree_view", "kind": "modal", "tags": []},
{"key": "codex_view", "kind": "modal", "tags": []},
{"key": "camp_esc_overlay", "kind": "modal", "tags": []}, # Esc 浮窗(卡⑤——登记于营地层与设置层之间,契约 3 栈语义正解)
{"key": "settings_overlay", "kind": "modal", "tags": []},
{"key": "status_panel", "kind": "modal", "tags": []},
{"key": "career_overlay", "kind": "modal", "tags": []},
{"key": "save_select_overlay", "kind": "modal", "tags": []}, # 选档界面(营地交互重做卡③——登记生涯同档)
{"key": "inter_overlay", "kind": "state", "tags": []},
{"key": "confirm_dialog", "kind": "modal", "tags": []},
{"key": "debug_overlay", "kind": "modal", "tags": [ModalStack.TAG_NON_LOCKING]},
{"key": "debug_badge", "kind": "float"}, # 调试入口全局浮层——末位=最顶绘制序;
# float 类不注册 ModalStack(open() 遮挡记账只隐藏登记层)→ 任何 UI 打开都不遮它
]
var screens: UiScreens
var battle: UiBattle
var modals: UiModals
func _init() -> void:
screens = UiScreens.new()
battle = UiBattle.new()
modals = UiModals.new()
# 合同层寻址(key→节点;纯查表不含层序语义——层序唯一事实源=LAYER_CONTRACT)
func node(key: String) -> Node:
match key:
"adventure_screen": return screens.adventure_screen
"menu_screen": return screens.menu_screen
"row_pacer": return screens.row_pacer
"legend_overlay": return modals.legend_overlay
"node_overlay": return modals.node_overlay
"level_screen": return modals.level_screen
"curio_overlay": return modals.curio_overlay
"end_overlay": return modals.end_overlay
"shop_overlay": return modals.shop_overlay
"camp_screen": return screens.camp_screen
"camp_scene": return modals.camp.scene
"forge_view": return modals.camp.forge
"treasure_view": return modals.camp.treasure
"tree_view": return modals.camp.tree
"codex_view": return modals.camp.codex
"camp_esc_overlay": return modals.camp.esc_overlay
"settings_overlay": return modals.settings_overlay
"status_panel": return modals.status_panel
"career_overlay": return modals.career_overlay
"save_select_overlay": return modals.save_select_overlay
"inter_overlay": return screens.inter_overlay
"confirm_dialog": return modals.confirm_dialog
"debug_overlay": return modals.debug_overlay
"debug_badge": return screens.debug_badge
return null
# 合同装配(_build_ui 尾调用):按 LAYER_CONTRACT 序统一落位——直接子层 move_child 到合同槽、
# 模态层按合同序登记;宿住层(host)树序随宿主只登记;成员层(shell)与屏壳同槽(屏壳占树位、成员占登记位)。
# 本函数是全仓唯一层序落位点(move_child 单口)——改层序只改 LAYER_CONTRACT。
func apply_layer_contract(root: Control) -> void:
var slot := 0
for entry: Dictionary in LAYER_CONTRACT:
var tags: Array[Variant] = entry.get("tags", [])
if entry.has("shell"):
var shell: Node = node(String(entry["shell"]))
var member: Node = node(String(entry["key"]))
if shell != null:
root.move_child(shell, slot)
slot += 1
if member != null:
modals.register_layer(member as Control, tags)
else:
push_error("[合同装配] 层缺失: %s" % String(entry["key"]))
continue
var layer: Node = node(String(entry["key"]))
if layer == null:
push_error("[合同装配] 层缺失: %s" % String(entry["key"]))
continue
if entry.has("host"):
modals.register_layer(layer as Control, tags)
continue
root.move_child(layer, slot)
slot += 1
if String(entry["kind"]) == "modal":
modals.register_layer(layer as Control, tags)