feat(m63-d): migrate Settings onto the shared chrome

This commit is contained in:
2026-09-14 02:52:00 +08:00
parent dcc64efd33
commit cfeb924b2f
2 changed files with 123 additions and 34 deletions
+86 -33
View File
@@ -7194,18 +7194,38 @@ func show_settings(category := "") -> void:
safe.add_theme_constant_override("margin_top", 12 if short_layout else 24)
safe.add_theme_constant_override("margin_bottom", 12 if short_layout else 24)
add_child(safe)
safe.add_child(_entry_chrome("SettingsFrame", "settings_frame"))
var settings_frame := PageChrome.new().configure("card")
settings_frame.name = "SettingsFrame"
settings_frame.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
safe.add_child(settings_frame)
# The full-page parchment card rolls 5.5% horizontally and 15% vertically;
# everything must live on the face between those edges.
var card_width := maxf(0.0, size.x - float(margin) * 2.0)
var card_height := maxf(0.0, size.y - (12.0 if short_layout else 24.0) * 2.0)
var card_inset_x := card_width * PageChrome.PANEL_EDGE_X + 8.0
var card_inset_y := card_height * PageChrome.PANEL_EDGE_Y + 8.0
var face := MarginContainer.new()
face.name = "SettingsFace"
face.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
face.add_theme_constant_override("margin_left", int(card_inset_x))
face.add_theme_constant_override("margin_right", int(card_inset_x))
face.add_theme_constant_override("margin_top", int(card_inset_y))
face.add_theme_constant_override("margin_bottom", int(card_inset_y))
safe.add_child(face)
var outer := VBoxContainer.new()
outer.name = "SettingsOuter"
outer.add_theme_constant_override("separation", 8)
safe.add_child(outer)
face.add_child(outer)
var heading := HBoxContainer.new()
heading.name = "SettingsHeading"
outer.add_child(heading)
var title := _label(_tr("设置", "SETTINGS"), _scaled(24 if short_layout else 26), Color("#f5ead0"))
var title := _label(_tr("设置", "SETTINGS"), UITokens.font_size("heading", _entry_text_scale()), PageChrome.INK)
title.name = "SettingsTitle"
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
heading.add_child(title)
heading.add_child(_label(_tr("来源:标题首页", "Caller: Title"), _scaled(12), Color("#e8d39d")))
var caller_label := _label(_tr("来源:标题首页", "Caller: Title"), UITokens.font_size("micro", _entry_text_scale()), PageChrome.INK_SOFT)
caller_label.name = "SettingsCaller"
heading.add_child(caller_label)
var workspace := HBoxContainer.new()
workspace.name = "SettingsWorkspace"
workspace.size_flags_vertical = Control.SIZE_EXPAND_FILL
@@ -7249,7 +7269,10 @@ func show_settings(category := "") -> void:
workspace.add_child(scroll)
var content := VBoxContainer.new()
content.name = "SettingsContent"
content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
# A 20:1 shared plate would show metre-wide rolled ends; cap the reading
# column so plates stay in the authored aspect range.
content.custom_minimum_size.x = 720.0
content.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
content.add_theme_constant_override("separation", 6)
scroll.add_child(content)
_build_settings_category(content)
@@ -7257,7 +7280,7 @@ func show_settings(category := "") -> void:
footer.name = "SettingsFooter"
footer.add_theme_constant_override("separation", 8)
outer.add_child(footer)
var notice := _label(settings_notice, _scaled(12 if short_layout else 13), Color("#f0ca75"))
var notice := _label(settings_notice, UITokens.font_size("micro", _entry_text_scale()), UITokens.COLOR_DANGER)
notice.name = "SettingsNotice"
notice.size_flags_horizontal = Control.SIZE_EXPAND_FILL
footer.add_child(notice)
@@ -7301,17 +7324,17 @@ func _build_settings_category(content: VBoxContainer) -> void:
content.add_child(_choice_button("SettingDynamicRange", _tr("动态范围", "Dynamic range"), String(settings_draft.dynamic_range).capitalize(), cycle_dynamic_range))
"controls":
content.add_child(_settings_heading(_tr("控制", "CONTROLS")))
content.add_child(_label(_tr("触控、键鼠与控制器共享确认、取消和导航语义。", "Touch, keyboard/mouse and controller share confirm, cancel and navigation semantics."), _scaled(15), Color("#aebbc2")))
content.add_child(_label(_tr("触控、键鼠与控制器共享确认、取消和导航语义。", "Touch, keyboard/mouse and controller share confirm, cancel and navigation semantics."), UITokens.font_size("micro", _entry_text_scale()), PageChrome.INK_SOFT))
content.add_child(_slider_row("SettingHoldDuration", _tr("长按确认时间", "Hold duration"), float(settings_draft.hold_duration), 0.3, 1.5, 0.1, set_hold_duration))
content.add_child(_check_button("SettingVibration", _tr("震动", "Vibration"), bool(settings_draft.vibration), set_vibration))
content.add_child(_unavailable_row("SettingRemapUnavailable", _tr("按键重映射:DEV-1 仅提供默认入口映射;完整冲突检查属于后续控制页面", "Remapping: DEV-1 uses the default entry map; conflict-safe remapping belongs to the later Controls page")))
"language":
content.add_child(_settings_heading(_tr("语言与地区格式", "LANGUAGE & LOCALE")))
content.add_child(_choice_button("SettingLocale", _tr("界面语言", "Interface language"), _tr("简体中文", "English"), cycle_setting_locale))
content.add_child(_label(_tr("日期 2026-08-17 · 数字 1,234.5 · 文本可换行", "Date 2026-08-17 · Number 1,234.5 · Text may wrap"), _scaled(16), Color("#f5ead0")))
content.add_child(_label(_tr("日期 2026-08-17 · 数字 1,234.5 · 文本可换行", "Date 2026-08-17 · Number 1,234.5 · Text may wrap"), UITokens.font_size("micro", _entry_text_scale()), PageChrome.INK))
"credits":
content.add_child(_settings_heading(_tr("制作人员、许可与数据", "CREDITS, LICENSES & DATA")))
var credits := _label(_credits_text(), _scaled(14), Color("#f5ead0"))
var credits := _label(_credits_text(), UITokens.font_size("micro", _entry_text_scale()), PageChrome.INK)
credits.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
credits.size_flags_horizontal = Control.SIZE_EXPAND_FILL
content.add_child(credits)
@@ -7462,14 +7485,14 @@ func _next_float(options: Array, current: float) -> float:
func _settings_heading(text_value: String) -> Label:
return _label(text_value, _scaled(19), Color("#e8d39d"))
return _label(text_value, UITokens.font_size("label", _entry_text_scale()), PageChrome.INK)
func _slider_row(node_name: String, text_value: String, value: float, minimum: float, maximum: float, step: float, callback: Callable) -> HBoxContainer:
var row := HBoxContainer.new()
row.name = node_name
row.custom_minimum_size.y = 42
var label := _label("%s %.1f" % [text_value, value], _scaled(14), Color("#f5ead0"))
var label := _label("%s %.1f" % [text_value, value], UITokens.font_size("micro", _entry_text_scale()), PageChrome.INK)
label.custom_minimum_size.x = 190
row.add_child(label)
var slider := HSlider.new()
@@ -7480,9 +7503,10 @@ func _slider_row(node_name: String, text_value: String, value: float, minimum: f
slider.value = value
slider.custom_minimum_size.y = 24
slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
slider.add_theme_stylebox_override("slider", _flat_style(Color("#0d151d"), Color("#866f47"), 1, 3))
slider.add_theme_stylebox_override("grabber_area", _flat_style(Color("#73b9e7"), Color("#ead49b"), 1, 3))
slider.add_theme_stylebox_override("grabber_area_highlight", _flat_style(Color("#a9d9f2"), Color("#f5ead0"), 1, 3))
# No shared slider component exists yet; the track keeps token colours.
slider.add_theme_stylebox_override("slider", _flat_style(Color("#0d151d"), Color("#a8935f"), 1, 3))
slider.add_theme_stylebox_override("grabber_area", _flat_style(Color("#397681"), PageChrome.INK_SOFT, 1, 3))
slider.add_theme_stylebox_override("grabber_area_highlight", _flat_style(Color("#4f9fb0"), PageChrome.INK, 1, 3))
slider.value_changed.connect(callback)
row.add_child(slider)
return row
@@ -7753,16 +7777,18 @@ func _choice_button(node_name: String, label_text: String, value_text: String, c
button.tooltip_text = "%s: %s" % [label_text, value_text]
button.custom_minimum_size = Vector2(0, 48)
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var label := _button_label("ChoiceLabel", label_text, _scaled(15), Color("#f5ead0"))
var label := _button_label("ChoiceLabel", label_text, UITokens.font_size("label", _entry_text_scale()), PageChrome.INK)
label.anchor_left = PageChrome.PLATE_EDGE_X
label.anchor_right = 0.58
label.offset_left = 14.0
label.offset_left = 6.0
label.offset_right = -6.0
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
button.add_child(label)
var value := _button_label("ValueLabel", value_text, _scaled(14), Color("#202a31"))
var value := _button_label("ValueLabel", value_text, UITokens.font_size("micro", _entry_text_scale()), PageChrome.INK)
value.anchor_left = 0.58
value.anchor_right = 1.0 - PageChrome.PLATE_EDGE_X
value.offset_left = 6.0
value.offset_right = -10.0
value.offset_right = -6.0
button.add_child(value)
return button
@@ -7771,9 +7797,11 @@ func _action_button(node_name: String, text_value: String, callback: Callable) -
var button := _entry_button_base(node_name, callback, "action_primary")
button.tooltip_text = text_value
button.custom_minimum_size = Vector2(UITokens.command_width("primary"), UITokens.command_height("primary"))
var label := _button_label("ButtonLabel", text_value, _scaled(16), Color("#f5ead0"))
label.offset_left = 46.0
label.offset_right = -10.0
var label := _button_label("ButtonLabel", text_value, UITokens.font_size("label", _entry_text_scale()), PageChrome.INK)
label.anchor_left = PageChrome.PLATE_EDGE_X
label.anchor_right = 1.0 - PageChrome.PLATE_EDGE_X
label.offset_left = 6.0
label.offset_right = -6.0
button.add_child(label)
return button
@@ -7782,9 +7810,11 @@ func _tool_button(node_name: String, text_value: String, callback: Callable) ->
var button := _entry_button_base(node_name, callback, "tool")
button.tooltip_text = text_value
button.custom_minimum_size = Vector2(UITokens.command_width("secondary"), UITokens.command_height("secondary"))
var label := _button_label("ButtonLabel", text_value, _scaled(14), Color("#f5ead0"))
label.offset_left = 16.0
label.offset_right = -10.0
var label := _button_label("ButtonLabel", text_value, UITokens.font_size("micro", _entry_text_scale()), PageChrome.INK)
label.anchor_left = PageChrome.PLATE_EDGE_X
label.anchor_right = 1.0 - PageChrome.PLATE_EDGE_X
label.offset_left = 6.0
label.offset_right = -6.0
button.add_child(label)
return button
@@ -7798,9 +7828,28 @@ func _check_button(node_name: String, text_value: String, enabled: bool, callbac
check.flat = true
for style_name in ["normal", "hover", "pressed", "disabled", "focus", "hover_pressed"]:
check.add_theme_stylebox_override(style_name, StyleBoxEmpty.new())
check.add_child(_entry_chrome("Chrome", "toggle"))
var label := _button_label("ButtonLabel", text_value, _scaled(14), Color("#f5ead0"))
label.offset_left = 14.0
# The switch state is a shared pip so on/off reads without the old
# bespoke toggle art.
var chrome := PageChrome.new().configure("command_plate", {"state": "secondary"})
chrome.name = "Chrome"
chrome.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
check.add_child(chrome)
var switch_pip := PageChrome.new().configure("pip", {"shape": "diamond", "filled": enabled})
switch_pip.name = "SwitchPip"
switch_pip.anchor_left = 1.0
switch_pip.anchor_right = 1.0
switch_pip.anchor_top = 0.5
switch_pip.anchor_bottom = 0.5
switch_pip.offset_left = -54.0
switch_pip.offset_right = -22.0
switch_pip.offset_top = -14.0
switch_pip.offset_bottom = 14.0
check.add_child(switch_pip)
check.toggled.connect(func(on: bool) -> void: switch_pip.configure("pip", {"shape": "diamond", "filled": on}).queue_redraw())
var label := _button_label("ButtonLabel", text_value, UITokens.font_size("micro", _entry_text_scale()), PageChrome.INK)
label.anchor_left = PageChrome.PLATE_EDGE_X
label.anchor_right = 1.0 - PageChrome.PLATE_EDGE_X
label.offset_left = 6.0
label.offset_right = -52.0
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
@@ -7815,7 +7864,13 @@ func _entry_button_base(node_name: String, callback: Callable, variant: String)
button.flat = true
for style_name in ["normal", "hover", "pressed", "disabled", "focus", "hover_pressed"]:
button.add_theme_stylebox_override(style_name, StyleBoxEmpty.new())
button.add_child(_entry_chrome("Chrome", variant))
# M63-D: entry-family buttons use the shared hand-drawn plate; the authored
# `Chrome` node name and variant meta stay for the focused contract.
var plate_state := "primary" if variant == "action_primary" else "secondary"
var chrome := PageChrome.new().configure("command_plate", {"state": plate_state})
chrome.name = "Chrome"
chrome.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
button.add_child(chrome)
button.set_meta("entry_chrome_variant", variant)
button.pressed.connect(callback, CONNECT_DEFERRED)
return button
@@ -7839,13 +7894,11 @@ func _set_entry_button_disabled(button: Button, disabled: bool, selected := fals
if label == null:
continue
if selected:
label.add_theme_color_override("font_color", Color("#202a31"))
label.add_theme_color_override("font_color", PageChrome.INK)
elif disabled:
label.add_theme_color_override("font_color", Color("#4f565b") if child_name == "ValueLabel" else Color("#89939a"))
elif child_name == "ValueLabel":
label.add_theme_color_override("font_color", Color("#202a31"))
label.add_theme_color_override("font_color", UITokens.COLOR_MUTED)
else:
label.add_theme_color_override("font_color", Color("#f5ead0"))
label.add_theme_color_override("font_color", PageChrome.INK)
func _set_entry_button_text(button: Button, text_value: String) -> void:
+37 -1
View File
@@ -52,6 +52,9 @@ func _run() -> void:
await _capture_setup(size, locale)
await _capture_title(size, locale, "fresh")
await _capture_title(size, locale, "recoverable")
if size == AUTHORITY_SIZE:
await _capture_settings(size, locale, "display")
await _capture_settings(size, locale, "audio")
var report_path := output_root.path_join("ink-violations-m63-entry.json")
var file := FileAccess.open(report_path, FileAccess.WRITE)
if file != null:
@@ -67,7 +70,7 @@ func _run() -> void:
return
if title_recoverable_ok:
print("ABG_M63_TITLE_RECOVERABLE_OK new_game=enabled continue=enabled")
print("ABG_M63_ENTRY_VISUAL_PROBE_OK sizes=2 locales=2 pages=boot,setup,title states=running,error,fresh,recoverable views=static,dynamic,final")
print("ABG_M63_ENTRY_VISUAL_PROBE_OK sizes=2 locales=2 pages=boot,setup,title,settings states=running,error,fresh,recoverable,display,audio views=static,dynamic,final")
quit(0)
@@ -231,6 +234,39 @@ func _capture_title(size: Vector2i, locale: String, state: String) -> void:
await process_frame
func _capture_settings(size: Vector2i, locale: String, category: String) -> void:
var viewport := SubViewport.new()
viewport.size = size
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
root.add_child(viewport)
var shell := EntryShell.new()
shell.auto_start = false
viewport.add_child(shell)
await _frames(3)
shell.settings = SettingsStore.new().defaults()
shell.settings.setup_completed = true
shell.settings.locale = locale
shell.size = Vector2(size)
shell.show_settings(category)
await _frames(4)
_scan_ink(shell, locale, "settings-%s-%dx%d" % [category, size.x, size.y], true)
await _save(viewport, "settings-%s-%dx%d-%s" % [category, size.x, size.y, locale], "final")
for node_name in ["SettingsTitle", "SettingsCaller", "SettingsNotice"]:
var control := shell.find_child(node_name, true, false) as CanvasItem
if control != null:
control.visible = false
var content := shell.find_child("SettingsContent", true, false) as Control
if content != null:
for child in content.get_children():
var canvas := child as CanvasItem
if canvas != null:
canvas.visible = false
await _frames(2)
await _save(viewport, "settings-%s-%dx%d-%s" % [category, size.x, size.y, locale], "static")
viewport.queue_free()
await process_frame
func _scan_ink(view: Control, locale: String, label: String, strict := true) -> void:
var violations := InkCheck.scan(view)
if not strict: