diff --git a/game/presentation/views/ui_kit.gd b/game/presentation/views/ui_kit.gd index 2b63f6c1..f6e30950 100644 --- a/game/presentation/views/ui_kit.gd +++ b/game/presentation/views/ui_kit.gd @@ -537,22 +537,43 @@ static func keystone_badge(text: String, icon_path := TEX_ICON_KEYSTONE, icon_px return KeystoneBadge.new(text, icon_path, icon_px) -# 按钮皮(常态/按压两态+墨字——缺位 = 引擎默认主题,素材批前逐位一致) +# 按钮皮·五态矩阵(迭代 26 T1——UI 交互与观感批;甲/乙案值=grilling 两轮八裁落文,逐实例 override 不动主题层) +# 悬停=乙案:常态图+modulate 提亮(0.06 档与 primary_button 现行 lightened(0.06) 同纪律,零新素材); +# 禁用=甲案:本族底+α0.45 幽灵化(与 font_disabled_color 同纪律),取代旧「disabled=按压图」错配; +# 焦点=甲案:INK 2px 内缩 1px 环(与 font_focus_color=INK 同源;引擎 focus 样式盒叠加绘制,不遮钮底) +const BUTTON_HOVER_LIFT := Color(1.06, 1.06, 1.06, 1.0) # 悬停提亮档(modulate 乘数>1=中间调提亮,高光像素封顶不漂) +const BUTTON_GHOST_ALPHA := 0.45 # 禁用幽灵化 α(与文字禁用同档) +const BUTTON_FOCUS_RING_W := 2.0 # 焦点环宽 px +const BUTTON_FOCUS_RING_INSET := 1.0 # 焦点环内缩 px(负 expand margin 实现) + +static func _focus_ring_sb() -> StyleBoxFlat: + var sb := StyleBoxFlat.new() + sb.bg_color = Color(0, 0, 0, 0) + sb.draw_center = false + sb.set_border_width_all(BUTTON_FOCUS_RING_W) + sb.border_color = INK + sb.set_expand_margin_all(-BUTTON_FOCUS_RING_INSET) + return sb + + +# 按钮皮(五态统一管线——常态/悬停/按压/禁用/焦点+墨字;缺位素材 = 引擎默认主题) static func _apply_button_skin(b: Button) -> void: var tex_n := load_tex(TEX_BUTTON_STONE) if tex_n == null: return var tex_p := load_tex(TEX_BUTTON_STONE_PRESSED) b.add_theme_stylebox_override("normal", _tex_sb(tex_n, 8.0)) - b.add_theme_stylebox_override("hover", _tex_sb(tex_n, 8.0)) + b.add_theme_stylebox_override("hover", _tex_sb(tex_n, 8.0, BUTTON_HOVER_LIFT)) if tex_p != null: b.add_theme_stylebox_override("pressed", _tex_sb(tex_p, 8.0)) - b.add_theme_stylebox_override("disabled", _tex_sb(tex_p, 8.0)) + b.add_theme_stylebox_override("disabled", + _tex_sb(tex_n, 8.0, Color(1, 1, 1, BUTTON_GHOST_ALPHA))) + b.add_theme_stylebox_override("focus", _focus_ring_sb()) b.add_theme_color_override("font_color", INK) b.add_theme_color_override("font_hover_color", INK) b.add_theme_color_override("font_pressed_color", INK) b.add_theme_color_override("font_focus_color", INK) - b.add_theme_color_override("font_disabled_color", Color(INK, 0.45)) + b.add_theme_color_override("font_disabled_color", Color(INK, BUTTON_GHOST_ALPHA)) # ── UI 落码批 M10 公共件(2026-10-04——bcard 竖卡工厂/拨杆开关/样式滑杆/动词按钮/tooltip 主题; @@ -578,10 +599,14 @@ static func primary_button(text: String, tip := "") -> Button: b.add_theme_stylebox_override("normal", sb) b.add_theme_stylebox_override("hover", panel_flat(CANDLE.lightened(0.06), Color8(110, 69, 52),RADIUS_OBJECT, 2, Vector4(10, 2, 10, 2))) b.add_theme_stylebox_override("pressed", panel_flat(Color8(214, 172, 88), Color8(110, 69, 52),RADIUS_OBJECT, 2, Vector4(10, 2, 10, 2))) + b.add_theme_stylebox_override("disabled", + panel_flat(Color(CANDLE, BUTTON_GHOST_ALPHA), Color(Color8(110, 69, 52), BUTTON_GHOST_ALPHA), RADIUS_OBJECT, 2, Vector4(10, 2, 10, 2))) + b.add_theme_stylebox_override("focus", _focus_ring_sb()) b.add_theme_color_override("font_color", Color8(58, 42, 8)) b.add_theme_color_override("font_hover_color", Color8(58, 42, 8)) b.add_theme_color_override("font_pressed_color", Color8(58, 42, 8)) b.add_theme_color_override("font_focus_color", Color8(58, 42, 8)) + b.add_theme_color_override("font_disabled_color", Color(Color8(58, 42, 8), BUTTON_GHOST_ALPHA)) if tip != "": b.tooltip_text = tip return b @@ -593,9 +618,16 @@ static func danger_button(text: String, tip := "", min_w := 216.0) -> Button: var sb := panel_flat(Color8(180, 78, 54), Color8(110, 42, 28),RADIUS_OBJECT, 2, Vector4(10, 2, 10, 2)) b.add_theme_stylebox_override("normal", sb) b.add_theme_stylebox_override("hover", panel_flat(Color8(196, 90, 62), Color8(110, 42, 28),RADIUS_OBJECT, 2, Vector4(10, 2, 10, 2))) + b.add_theme_stylebox_override("pressed", + panel_flat(Color8(180, 78, 54).darkened(0.18), Color8(110, 42, 28),RADIUS_OBJECT, 2, Vector4(10, 2, 10, 2))) + b.add_theme_stylebox_override("disabled", + panel_flat(Color(Color8(180, 78, 54), BUTTON_GHOST_ALPHA), Color(Color8(110, 42, 28), BUTTON_GHOST_ALPHA), RADIUS_OBJECT, 2, Vector4(10, 2, 10, 2))) + b.add_theme_stylebox_override("focus", _focus_ring_sb()) b.add_theme_color_override("font_color", Color8(255, 244, 224)) b.add_theme_color_override("font_hover_color", Color8(255, 244, 224)) b.add_theme_color_override("font_pressed_color", Color8(255, 244, 224)) + b.add_theme_color_override("font_focus_color", Color8(255, 244, 224)) + b.add_theme_color_override("font_disabled_color", Color(Color8(255, 244, 224), BUTTON_GHOST_ALPHA)) if tip != "": b.tooltip_text = tip return b diff --git a/game/smoke/smoke_all.gd b/game/smoke/smoke_all.gd index c023dcd0..e11c861d 100644 --- a/game/smoke/smoke_all.gd +++ b/game/smoke/smoke_all.gd @@ -107,6 +107,7 @@ func _run_core_smoke(db, rng) -> void: _smoke_playtest_logger() _smoke_battle_log_view() _smoke_global_theme() + _smoke_button_five_states() _smoke_encounter_roll() _smoke_attack_chain_fresh_pool() _smoke_clear_reward_chain() @@ -5456,6 +5457,80 @@ func _smoke_global_theme() -> void: tpanel.free(); tlabel.free(); cbx.free(); cbt.free(); pm.free(); ob.free(); lbl.free() +# ---- 按钮五态矩阵冒烟(迭代 26 T1——四工厂产物逐实例 override 断言;V1/V2)---- +func _smoke_button_five_states() -> void: + print("--- UI 按钮五态矩阵(四工厂五态样式盒)---") + var uikit_s = load("res://presentation/views/ui_kit.gd") + var states := ["normal", "hover", "pressed", "disabled", "focus"] + # 普通钮(verb_button 同走 button() 打底——同断言覆盖) + var b = uikit_s.button("测试") + for st in states: + check(b.has_theme_stylebox_override(st), "V1 普通钮 %s 样式盒非空" % st) + var n_sb: StyleBox = b.get_theme_stylebox("normal") + var h_sb: StyleBox = b.get_theme_stylebox("hover") + var p_sb: StyleBox = b.get_theme_stylebox("pressed") + var d_sb: StyleBox = b.get_theme_stylebox("disabled") + var f_sb: StyleBox = b.get_theme_stylebox("focus") + check(n_sb is StyleBoxTexture and h_sb is StyleBoxTexture and d_sb is StyleBoxTexture, + "V1 普通钮 normal/hover/disabled 均为石纹九宫格贴图样式盒") + # 悬停=乙案:modulate 提亮(≠常态 WHITE——乙案判据) + var h_mod: Color = (h_sb as StyleBoxTexture).modulate_color + check(h_mod != Color.WHITE and h_mod.r > 1.0, "V1 普通钮 hover=modulate 提亮(乙案,异于常态 WHITE)") + # 禁用=甲案:本族底+α0.45 幽灵化 + var d_mod: Color = (d_sb as StyleBoxTexture).modulate_color + check(is_equal_approx(d_mod.a, 0.45) and d_mod.r == 1.0 and d_mod.g == 1.0, + "V1 普通钮 disabled=本族底 α0.45 幽灵化(甲案)") + # 错配修正判据:disabled≠pressed(旧「禁用=按压图」) + check(d_sb != p_sb, "V1 普通钮 disabled≠pressed(旧错配已修正)") + # 焦点=甲案:INK 2px 内缩 1px 环、无底(叠加态不遮钮底) + check(f_sb is StyleBoxFlat, "V1 普通钮 focus 样式盒为扁平环(StyleBoxFlat)") + var fsb := f_sb as StyleBoxFlat + check(fsb.border_color == uikit_s.INK, "V1 焦点环色=INK(与 font_focus_color 同源)") + check(is_equal_approx(fsb.border_width_left, 2.0) and is_equal_approx(fsb.border_width_right, 2.0) + and is_equal_approx(fsb.border_width_top, 2.0) and is_equal_approx(fsb.border_width_bottom, 2.0), + "V1 焦点环宽=2px") + check(is_equal_approx(fsb.expand_margin_left, -1.0) and is_equal_approx(fsb.expand_margin_top, -1.0) + and is_equal_approx(fsb.expand_margin_right, -1.0) and is_equal_approx(fsb.expand_margin_bottom, -1.0), + "V1 焦点环内缩=1px") + check(not fsb.draw_center and fsb.bg_color.a < 0.001, "V1 焦点环无底(叠加态不遮钮底)") + b.free() + # 主钮:五态非空+本族平涂(pressed/disabled 非石纹)+disabled≠pressed+hover 提亮档承现行 + var pb = uikit_s.primary_button("测试") + for st in states: + check(pb.has_theme_stylebox_override(st), "V1 主钮 %s 样式盒非空" % st) + var ppn: StyleBox = pb.get_theme_stylebox("pressed") + var pdd: StyleBox = pb.get_theme_stylebox("disabled") + var phv: StyleBox = pb.get_theme_stylebox("hover") + check(ppn is StyleBoxFlat and pdd is StyleBoxFlat, "V1 主钮 pressed/disabled=本族平涂(非石纹)") + check((ppn as StyleBoxFlat).bg_color == Color8(214, 172, 88), "V1 主钮 pressed=烛光黄深档(现行值不动)") + check(is_equal_approx((pdd as StyleBoxFlat).bg_color.a, 0.45), "V1 主钮 disabled=本族底 α0.45 幽灵化") + check(pdd != ppn, "V1 主钮 disabled≠pressed") + check((phv as StyleBoxFlat).bg_color == uikit_s.CANDLE.lightened(0.06), "V1 主钮 hover=提亮档(承现行不动)") + pb.free() + # 危险钮:补本族 pressed(深档)+disabled 幽灵化+focus;pressed/disabled 非石纹 + var db = uikit_s.danger_button("测试") + for st in states: + check(db.has_theme_stylebox_override(st), "V1 危险钮 %s 样式盒非空" % st) + var dpr: StyleBox = db.get_theme_stylebox("pressed") + var dds: StyleBox = db.get_theme_stylebox("disabled") + check(dpr is StyleBoxFlat and dds is StyleBoxFlat, "V1 危险钮 pressed/disabled=本族平涂(非石纹,旧错配已修正)") + check((dpr as StyleBoxFlat).bg_color.r < 180.0 / 255.0, "V1 危险钮 pressed=深红深档(暗于常态)") + check(is_equal_approx((dds as StyleBoxFlat).bg_color.a, 0.45), "V1 危险钮 disabled=本族底 α0.45 幽灵化") + check(dds != dpr, "V1 危险钮 disabled≠pressed") + db.free() + # V2 主题红线维持(Button 类型词条零接触+focus 族词条零定义)——与 _smoke_global_theme 同判据复述 + var th := ThemeDB.get_project_theme() + if th != null: + check(not th.get_type_list().has("Button"), "V2 红线维持 Button 类型词条零接触") + var focus_hits := "" + for t in th.get_type_list(): + for nm in (th.get_stylebox_list(t) + th.get_icon_list(t) + th.get_color_list(t) + + th.get_font_list(t) + th.get_font_size_list(t) + th.get_constant_list(t)): + if "focus" in String(nm): + focus_hits += "%s/%s " % [t, nm] + check(focus_hits == "", "V2 红线维持 focus 族词条零定义%s" % ("" if focus_hits == "" else "(违例:" + focus_hits + ")")) + + # ---- 存档序列化冒烟(SaveManager——读写往返/新档合法/余额拒花/锻造出域拒/高版本拒读禁写/ # 损坏兜底/迁移链/域界干净/摘要 cap/摘要集成/生涯终身计数域 v6)。测试文件统一 user://smoke_save_*.json 隔离, # 段首清场+段尾清理——绝不碰 user://save.json(红线)。