# VERTICAL SLICE - NOT FOR PRODUCTION # 实现 GDD:design/ux/battle.md(D 区 AP 条 44px——点阵+数字〔pattern 5 点阵资源显示〕、 # 停手按钮居左、图例+弃图刷新按钮居右〔雷图右上角〕;弃图刷新确认微交互与常规确认不同位 # 〔pattern 7 破坏性确认异位:RAP 扣费 · 旧板旗作废显式代价〕)。 # Date: 2026-09-12 # 高内聚边界:纯视图——意图经信号外发(stop_pressed/refresh_confirmed/legend_toggled), # 状态由组合根经 setter 注入;刷新可用性预判 = RAP≥8 读数(行动经济 无推送信号——每次调用返回后重查)。 class_name ApBarView extends PanelContainer signal stop_pressed signal refresh_confirmed signal legend_toggled const COL_GOLD := UiKit.GOLD const COL_DOT_OFF := UiKit.DOT_OFF const COL_INK := UiKit.INK var _dots: HBoxContainer var _ap_label: Label var _btn_stop: Button var _btn_legend: Button var _btn_refresh: Button var _refresh_sub: Label var _confirm_row: HBoxContainer var _confirm_lab: Label var refresh_cost: int = 0 # 表值驱动(装配经 set_refresh_cost 注入 ActionEconomyTable.rap_refresh_cost) var _confirm_armed := false var _arm_tween: Tween func _init() -> void: custom_minimum_size = Vector2(0, 44) var sb := UiKit.panel_flat(UiKit.PANEL_DATA, UiKit.PANEL_BORDER, 0, 1, Vector4(8, 4, 8, 4)) add_theme_stylebox_override("panel", sb) var row := HBoxContainer.new() row.add_theme_constant_override("separation", 8) add_child(row) _dots = HBoxContainer.new() _dots.add_theme_constant_override("separation", 3) _dots.size_flags_vertical = Control.SIZE_SHRINK_CENTER row.add_child(_dots) _ap_label = UiKit.label("AP 0/0", 16, true) _ap_label.size_flags_vertical = Control.SIZE_SHRINK_CENTER row.add_child(_ap_label) _btn_stop = UiKit.button("停手") _btn_stop.custom_minimum_size = Vector2(64, 0) _btn_stop.size_flags_vertical = Control.SIZE_SHRINK_CENTER _btn_stop.pressed.connect(func(): stop_pressed.emit()) row.add_child(_btn_stop) var spacer := Control.new() spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL row.add_child(spacer) # 破坏性确认异位(pattern 7):确认 chips 出现在刷新按钮左方——与常规"按钮自身确认"不同位 _confirm_row = HBoxContainer.new() _confirm_row.add_theme_constant_override("separation", 4) _confirm_row.visible = false row.add_child(_confirm_row) _confirm_lab = UiKit.label("RAP−%d · 旧板旗作废" % refresh_cost, 14, true) _confirm_lab.add_theme_color_override("font_color", COL_INK) _confirm_row.add_child(_confirm_lab) var confirm_btn := UiKit.button("确认弃图") confirm_btn.pressed.connect(_disarm_and_fire) _confirm_row.add_child(confirm_btn) _btn_legend = UiKit.button("图例") _btn_legend.custom_minimum_size = Vector2(56, 0) _btn_legend.size_flags_vertical = Control.SIZE_SHRINK_CENTER _btn_legend.pressed.connect(func(): legend_toggled.emit()) row.add_child(_btn_legend) var refresh_box := VBoxContainer.new() refresh_box.add_theme_constant_override("separation", 0) refresh_box.size_flags_vertical = Control.SIZE_SHRINK_CENTER row.add_child(refresh_box) _btn_refresh = UiKit.button("弃图刷新") _btn_refresh.pressed.connect(_on_refresh_pressed) refresh_box.add_child(_btn_refresh) _refresh_sub = UiKit.label("RAP−%d · 剩 0 次" % refresh_cost, 14, false) _refresh_sub.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER refresh_box.add_child(_refresh_sub) # ---- setter 面(组合根每次核心调用返回后重查注入——行动经济 无推送信号) ---- func set_ap(ap: int, ap_max: int) -> void: while _dots.get_child_count() < ap_max: _dots.add_child(_make_dot()) while _dots.get_child_count() > ap_max: var last: Control = _dots.get_child(_dots.get_child_count() - 1) _dots.remove_child(last) last.queue_free() for i in _dots.get_child_count(): var d: ColorRect = _dots.get_child(i) d.color = COL_GOLD if i < ap else COL_DOT_OFF _ap_label.text = "AP %d/%d" % [ap, ap_max] func set_refresh_cost(cost: int) -> void: refresh_cost = cost _confirm_lab.text = "RAP−%d · 旧板旗作废" % cost func set_refresh_state(remaining: int, ready: bool) -> void: _refresh_sub.text = "RAP−%d · 剩 %d 次" % [refresh_cost, remaining] _btn_refresh.disabled = not ready if not ready: _disarm() func set_stop_enabled(on: bool) -> void: _btn_stop.disabled = not on func set_legend_enabled(on: bool) -> void: _btn_legend.disabled = not on # 探针/装配复用:刷新按钮可用性(预判 = RAP 足额 + 上限未到) func is_refresh_ready() -> bool: return not _btn_refresh.disabled # 探针接缝(ADR-0004"合成输入走真实翻译出口"口径):刷新按钮点击 → 确认 chips 全链路 func press_refresh_for_probe() -> void: _on_refresh_pressed() func confirm_visible() -> bool: return _confirm_row.visible func press_confirm_for_probe() -> void: if _confirm_armed: _disarm_and_fire() func refresh_remaining_text() -> String: return _refresh_sub.text # ---- 确认微交互(pattern 7 异位:常规确认 = 按钮自身;本确认 = 左侧独立 chips) ---- func _on_refresh_pressed() -> void: if _btn_refresh.disabled: return _confirm_row.visible = true _confirm_armed = true if _arm_tween != null and _arm_tween.is_valid(): _arm_tween.kill() _arm_tween = create_tween() _arm_tween.tween_interval(4.0) _arm_tween.tween_callback(_disarm) func _disarm_and_fire() -> void: _disarm() refresh_confirmed.emit() func _disarm() -> void: _confirm_armed = false _confirm_row.visible = false # 资源面拒绝反馈(pattern 1 resource_face 腿):AP 数字脉冲 func pulse_ap() -> void: var tw := create_tween() tw.tween_property(_ap_label, "modulate", Color(1.0, 0.4, 0.3), UiKit.motion(0.1)) tw.tween_property(_ap_label, "modulate", Color(1, 1, 1), UiKit.motion(0.25)) func _make_dot() -> ColorRect: var d := ColorRect.new() d.custom_minimum_size = Vector2(10, 10) d.color = COL_DOT_OFF d.mouse_filter = Control.MOUSE_FILTER_IGNORE return d