Close the 0.9.3 UI polish milestone
Full build / Import + headless tests (push) Successful in 36s
Full build / Full desktop build + optional release (push) Skipped

Add deterministic captures 14-21 for the remaining screen-design states, fix the panel/button layout issues they exposed, and record 21/21 compare and judge results. Bump the source to 0.9.3 and move the completed milestone to DONE.md.
This commit is contained in:
zwitschi committed 2026-11-02 17:57:40 +01:00
1 parent e805a91ad3
commit c1cd4898e8
32 files changed
+440 -160

No files matched your search

+2
View File
@@ -107,6 +107,7 @@ func _init() -> void:
var buttons := HBoxContainer.new()
vbox.add_child(buttons)
action_button = Button.new()
action_button.custom_minimum_size = Vector2(190, 0)
action_button.text = Strings.lookup("ui.radio_send_assist")
action_button.button_down.connect(func(): _start_hold())
action_button.button_up.connect(func(): _stop_hold(false))
@@ -114,6 +115,7 @@ func _init() -> void:
UiStyles.apply_button(action_button, 16)
buttons.add_child(action_button)
cancel_button = Button.new()
cancel_button.custom_minimum_size = Vector2(140, 0)
cancel_button.text = Strings.lookup("ui.radio_cancel")
cancel_button.pressed.connect(func(): cancelled.emit())
UiStyles.apply_button(cancel_button, 16)
+28 -16
View File
@@ -76,14 +76,25 @@ func _build() -> void:
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
column.add_child(title)
var scroll := ScrollContainer.new()
scroll.name = "SettingsScroll"
scroll.custom_minimum_size = Vector2(640, 500)
scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
column.add_child(scroll)
var content := VBoxContainer.new()
content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
content.add_theme_constant_override("separation", 12)
scroll.add_child(content)
var sens_row := VBoxContainer.new()
column.add_child(sens_row)
content.add_child(sens_row)
_sensitivity_value = _add_label_row(sens_row, "Mouse look sensitivity")
_sensitivity = _add_slider(sens_row, 0.0005, 0.0060, 0.0001)
_sensitivity.value_changed.connect(_on_sensitivity_changed)
var font_row := VBoxContainer.new()
column.add_child(font_row)
content.add_child(font_row)
_font_scale_value = _add_label_row(font_row, "HUD font scale")
_font_scale = _add_slider(font_row, 0.75, 1.75, 0.05)
_font_scale.value_changed.connect(_on_font_scale_changed)
@@ -91,15 +102,15 @@ func _build() -> void:
_invert_y = CheckButton.new()
_invert_y.text = Strings.lookup("ui.settings_invert")
_invert_y.toggled.connect(_on_invert_y_toggled)
column.add_child(_invert_y)
content.add_child(_invert_y)
_head_bob = CheckButton.new()
_head_bob.text = Strings.lookup("ui.settings_head_bob")
_head_bob.toggled.connect(_on_head_bob_toggled)
column.add_child(_head_bob)
content.add_child(_head_bob)
var diff_row := HBoxContainer.new()
column.add_child(diff_row)
content.add_child(diff_row)
var diff_label := Label.new()
diff_label.text = Strings.lookup("ui.settings_difficulty")
diff_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
@@ -111,13 +122,13 @@ func _build() -> void:
diff_row.add_child(_difficulty)
var audio_row := HBoxContainer.new()
column.add_child(audio_row)
content.add_child(audio_row)
audio_row.add_child(_volume_label("Master volume"))
_master = _add_slider(audio_row, 0.0, 1.0, 0.05)
_master = _add_slider(audio_row, 0.0, 1.0, 0.05, 120.0)
audio_row.add_child(_volume_label("SFX"))
_sfx = _add_slider(audio_row, 0.0, 1.0, 0.05)
_sfx = _add_slider(audio_row, 0.0, 1.0, 0.05, 120.0)
audio_row.add_child(_volume_label("Ambience"))
_ambience = _add_slider(audio_row, 0.0, 1.0, 0.05)
_ambience = _add_slider(audio_row, 0.0, 1.0, 0.05, 120.0)
_master.value_changed.connect(func(v): settings["master_volume"] = v)
_sfx.value_changed.connect(func(v): settings["sfx_volume"] = v)
_ambience.value_changed.connect(func(v): settings["ambience_volume"] = v)
@@ -125,15 +136,15 @@ func _build() -> void:
_reduce_motion = CheckButton.new()
_reduce_motion.text = Strings.lookup("ui.settings_reduce_motion")
_reduce_motion.toggled.connect(func(v): settings["reduce_motion"] = v)
column.add_child(_reduce_motion)
content.add_child(_reduce_motion)
_captions = CheckButton.new()
_captions.text = Strings.lookup("ui.settings_captions")
_captions.toggled.connect(func(v): settings["captions_enabled"] = v)
column.add_child(_captions)
content.add_child(_captions)
var replay_row := HBoxContainer.new()
replay_row.alignment = BoxContainer.ALIGNMENT_CENTER
column.add_child(replay_row)
content.add_child(replay_row)
var replay := Button.new()
replay.name = "ReplayTutorialButton"
replay.text = Strings.lookup("ui.settings_replay")
@@ -151,12 +162,12 @@ func _build() -> void:
controls_title.text = Strings.lookup("ui.settings_controls_help")
controls_title.add_theme_font_size_override("font_size", 13)
controls_title.modulate = Color(0.75, 0.8, 0.9)
column.add_child(controls_title)
content.add_child(controls_title)
var grid := GridContainer.new()
grid.columns = 4
grid.add_theme_constant_override("h_separation", 10)
grid.add_theme_constant_override("v_separation", 6)
column.add_child(grid)
content.add_child(grid)
for action in InputBindings.REMAPPABLE:
var label := Label.new()
label.text = str(action).replace("_", " ").capitalize()
@@ -207,12 +218,13 @@ func _volume_label(text: String) -> Label:
label.custom_minimum_size = Vector2(82, 0)
return label
func _add_slider(parent: Control, min_v: float, max_v: float, step: float) -> HSlider:
func _add_slider(parent: Control, min_v: float, max_v: float, step: float,
min_width: float = 420.0) -> HSlider:
var slider := HSlider.new()
slider.min_value = min_v
slider.max_value = max_v
slider.step = step
slider.custom_minimum_size = Vector2(420, 24)
slider.custom_minimum_size = Vector2(min_width, 24)
parent.add_child(slider)
return slider
+7 -4
View File
@@ -36,11 +36,14 @@ func _init() -> void:
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
root.add_child(dim)
var center_host := CenterContainer.new()
center_host.set_anchors_preset(Control.PRESET_FULL_RECT)
root.add_child(center_host)
var center := VBoxContainer.new()
center.set_anchors_preset(Control.PRESET_CENTER)
center.custom_minimum_size = Vector2(760, 0)
center.alignment = BoxContainer.ALIGNMENT_CENTER
center.add_theme_constant_override("separation", 12)
root.add_child(center)
center.add_theme_constant_override("separation", 8)
center_host.add_child(center)
var title := Label.new()
title.text = Strings.lookup("review.title")
@@ -92,7 +95,7 @@ func _init() -> void:
center.add_child(_quit_button)
func _style_review_button(button: Button) -> void:
button.custom_minimum_size = Vector2(300, 52)
button.custom_minimum_size = Vector2(300, 46)
UiStyles.apply_button(button, 22)
func show_review(review: Dictionary, scenario: Resource, history: Array = [],
+5
View File
@@ -27,6 +27,11 @@ static func apply_button(button: Button, font_size: int = 0, compact: bool = fal
button.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
var margin_h := 12 if compact else 18
var margin_v := 7 if compact else 10
# clip_text removes the text-width contribution from the minimum size, so
# give unconstrained buttons a sane target width instead of collapsing them
# to the style margins (the radio action used to become a blank square).
if button.custom_minimum_size.x <= 0.0:
button.custom_minimum_size.x = 96.0 if compact else 160.0
var normal := _box(SURFACE, margin_h, margin_v)
var hover := _box(SURFACE_HOVER, margin_h, margin_v)
var pressed := _box(SURFACE_PRESSED, margin_h, margin_v)