Files
gplan-2/game/presentation/ui_registry.gd
T

124 lines
6.7 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)+模态编排件 ModalFlow 直驻(自 UiModals 升格——构造时点
## 与今等价:注册面构造点先于装配)、模态登记唯一口 register_layer(随登记职责迁驻)、
## 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
var flow: ModalFlow # 模态编排件直驻注册面(升格自 UiModals——查询/钩子 Callable 由 _build_modal_flow 注入,注入时点不变)
func _init() -> void:
screens = UiScreens.new()
battle = UiBattle.new()
modals = UiModals.new()
flow = ModalFlow.new()
# 模态登记唯一口(自 ui_modals.gd 逐字迁驻——登记职责随编排域归注册面单点)
func register_layer(m: Control, tags: Array = []) -> void:
# 撑满宿主(Control 默认锚 = 0×0——全屏变暗层与居中布局整体失效;route 选路层预览截图实证后
# 统一收口:六个模态同病,探针经信号直发绕过真实点击从未暴露。anchors_and_offsets 而非 anchors
# ——后者会把控件重置回最小内容尺寸,ui_assembler 头注同款纪律)
m.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
flow.register(m, tags) # 排除组随层登记(non_locking=调试浮窗/screen_state=关卡地图屏)
# 合同层寻址(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.run.legend_overlay
"node_overlay": return modals.run.node_overlay
"level_screen": return modals.run.level_screen
"curio_overlay": return modals.run.curio_overlay
"end_overlay": return modals.run.end_overlay
"shop_overlay": return modals.menu.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.menu.settings_overlay
"status_panel": return modals.run.status_panel
"career_overlay": return modals.menu.career_overlay
"save_select_overlay": return modals.menu.save_select_overlay
"inter_overlay": return screens.inter_overlay
"confirm_dialog": return modals.menu.confirm_dialog
"debug_overlay": return modals.menu.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:
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"):
register_layer(layer as Control, tags)
continue
root.move_child(layer, slot)
slot += 1
if String(entry["kind"]) == "modal":
register_layer(layer as Control, tags)