feat(ui): dialogue UI hardening and examine result overlay (#174)

Confrontation options use RichTextLabel with italic tags for
first-person voice (D-063). Examine result overlay auto-dismisses
after 5s with confidence-based color tinting. Dismisses when
dialogue opens. D-062 invisible locked options confirmed correct.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-25 02:29:55 +01:00
co-authored by Claude Opus 4.6
parent eeb82535f6
commit 9b80ff69c3
4 changed files with 228 additions and 18 deletions
+44 -18
View File
@@ -354,26 +354,45 @@ func _show_options(options: Array) -> void:
var raw_text: String = opt.get("text", "")
var is_confrontation: bool = opt.get("confrontation", false)
var label := Label.new()
label.add_theme_font_size_override("font_size", 14)
label.add_theme_color_override("font_color", Constants.INSERT_COLOR_TEXT)
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
label.mouse_filter = Control.MOUSE_FILTER_STOP
label.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
var numbered_text := "%d. %s" % [i + 1, raw_text]
label.text = numbered_text
# D-063: Confrontation options render italic — first-person voice, weighted differently.
# Use RichTextLabel with BBCode [i] tags for confrontation; plain Label for standard.
var ctrl: Control
if is_confrontation:
var rtl := RichTextLabel.new()
rtl.bbcode_enabled = true
rtl.fit_content = true
rtl.scroll_active = false
rtl.add_theme_font_size_override("normal_font_size", 14)
rtl.add_theme_color_override("default_color", Color(
Constants.INSERT_COLOR_TEXT.r * 1.08,
Constants.INSERT_COLOR_TEXT.g * 0.96,
Constants.INSERT_COLOR_TEXT.b * 0.90,
1.0
)) # Slight warm tint for confrontation weight
rtl.mouse_filter = Control.MOUSE_FILTER_STOP
rtl.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
rtl.text = "[i]%d. %s[/i]" % [i + 1, raw_text]
ctrl = rtl
else:
var label := Label.new()
label.add_theme_font_size_override("font_size", 14)
label.add_theme_color_override("font_color", Constants.INSERT_COLOR_TEXT)
label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
label.mouse_filter = Control.MOUSE_FILTER_STOP
label.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
label.text = "%d. %s" % [i + 1, raw_text]
ctrl = label
var idx := i
label.gui_input.connect(func(event: InputEvent):
ctrl.gui_input.connect(func(event: InputEvent):
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
_on_option_pressed(idx)
)
label.mouse_entered.connect(_make_hover_on(label))
label.mouse_exited.connect(_make_hover_off(label))
ctrl.mouse_entered.connect(_make_hover_on(ctrl))
ctrl.mouse_exited.connect(_make_hover_off(ctrl))
options_container.add_child(label)
_option_controls.append(label)
options_container.add_child(ctrl)
_option_controls.append(ctrl)
_option_response_ids.append(opt.get("response_id", ""))
_option_texts.append(raw_text)
_option_is_confrontation.append(is_confrontation)
@@ -623,11 +642,18 @@ func _clear_options() -> void:
# Hover callbacks
static func _make_hover_on(label: Control) -> Callable:
static func _make_hover_on(ctrl: Control) -> Callable:
return func():
label.add_theme_color_override("font_color", Constants.INSERT_COLOR_HOVER)
# RichTextLabel uses "default_color"; Label uses "font_color"
if ctrl is RichTextLabel:
ctrl.add_theme_color_override("default_color", Constants.INSERT_COLOR_HOVER)
else:
ctrl.add_theme_color_override("font_color", Constants.INSERT_COLOR_HOVER)
static func _make_hover_off(label: Control) -> Callable:
static func _make_hover_off(ctrl: Control) -> Callable:
return func():
label.add_theme_color_override("font_color", Constants.INSERT_COLOR_TEXT)
if ctrl is RichTextLabel:
ctrl.add_theme_color_override("default_color", Constants.INSERT_COLOR_TEXT)
else:
ctrl.add_theme_color_override("font_color", Constants.INSERT_COLOR_TEXT)