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

64 lines
2.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.
# VERTICAL SLICE - NOT FOR PRODUCTION
# 实现 GDD:design/ux/interaction-patterns.md(pattern 6 模态 overlay 层级纪律)。
# Date: 2026-09-12(code-review 修复批——自 main.gd 拆出,规范 1.1 状态装配独立成类)
# 模态层级状态机:登记序 = 树序 = z 遮挡序;打开时显式隐藏树序在其上方的可见层、关闭恢复
# (缺陷⑤纪律载体:功能存在 ≠ 功能可达——遮挡关系不得靠树序巧合)。
# 纯逻辑零节点构建——组合根持有本类并喂入 Control;不持久化核心状态。
extends RefCounted
var _list: Array[Control] = [] # 登记序 = z 遮挡序(低 → 高)
var _occluded := {} # modal → 被其隐藏的上方层(关闭恢复)
func register(m: Control) -> void:
_list.append(m)
func open(m: Control) -> void:
var hidden: Array[Control] = []
var idx := _list.find(m)
for i in range(idx + 1, _list.size()):
var higher: Control = _list[i]
if is_instance_valid(higher) and higher.visible:
higher.visible = false
hidden.append(higher)
_occluded[m] = hidden
m.visible = true
func close(m: Control) -> void:
m.visible = false
for h in _occluded.get(m, []):
if is_instance_valid(h):
h.visible = true
_occluded.erase(m)
# 开态查询(T3 模态收口批 2026-10-02——组合根输入锁唯一判据:登记册上是否有任一层处于开态;
# 可见性即开态,与 open/close 记账同源——组合根不再手工罗列各层)
func has_open() -> bool:
for m in _list:
if is_instance_valid(m) and m.visible:
return true
return false
# 排除式开态查询(迭代 17 卡③ 2026-10-06——暂停层入口守卫判据):skip 层自身的开态不计入
#(关卡地图屏系登记册模态成员=常态屏态,其上的地图屏角标必须可点;其余任一层开着=角标置灰)。
# 只读查询零副作用——登记序/开合记账语义零改动。
func has_open_excluding(skip: Control) -> bool:
return has_open_excluding_any([skip])
# 多排除式开态查询(迭代 18 卡⑦ T2 防护——调试浮窗对局中可开后,棋盘输入锁与暂停角标置灰
# 判据须同时排除调试浮窗自身〔否则 DS_DEBUG 默认开×遮挡复活×has_open 组合=棋盘永久锁死——
# 审计🔴 S1+ 停机点防线〕;地图屏场景=地图屏+调试浮窗双排除)。语义同 has_open_excluding,
# skip 集参数化;只读查询零副作用,登记序/开合记账语义零改动。
func has_open_excluding_any(skips: Array) -> bool:
for m in _list:
if skips.has(m):
continue
if is_instance_valid(m) and m.visible:
return true
return false