Add wrapping keyboard and gamepad focus rings
- Link every modal's enabled controls into a wrapping UiFocus ring and give each screen a default focus target. - Add gamepad A/B bindings for ui_accept/ui_cancel; include Start menu footer actions and Continue in its focus ring. - Skip hidden/disabled controls, close focus traps via per-modal cancel behavior, and return review to the menu on cancel. - Record the focus audit and add regression coverage.
This commit is contained in:
1 parent
9692f262f1
commit
8f65751975
17 files changed
+262
-76
No files matched your search
@@ -11,6 +11,7 @@ const Rules := preload("res://src/core/rules.gd")
|
||||
const Strings := preload("res://src/core/strings.gd")
|
||||
const UiArt := preload("res://src/game/ui/art.gd")
|
||||
const UiStyles := preload("res://src/game/ui/ui_styles.gd")
|
||||
const UiFocus := preload("res://src/game/ui/ui_focus.gd")
|
||||
|
||||
var panel: PanelContainer
|
||||
var npc_name_label: Label
|
||||
@@ -19,6 +20,8 @@ var desc_edit: LineEdit
|
||||
var weapons_check: CheckBox
|
||||
var danger_option: OptionButton
|
||||
var action_button: Button
|
||||
var cancel_button: Button
|
||||
var _focus_controls: Array[Control] = []
|
||||
var hold_hint: Label
|
||||
var status_label: Label
|
||||
|
||||
@@ -110,11 +113,14 @@ func _init() -> void:
|
||||
action_button.pressed.connect(_on_action_pressed)
|
||||
UiStyles.apply_button(action_button, 16)
|
||||
buttons.add_child(action_button)
|
||||
var cancel_btn := Button.new()
|
||||
cancel_btn.text = Strings.lookup("ui.radio_cancel")
|
||||
cancel_btn.pressed.connect(func(): cancelled.emit())
|
||||
UiStyles.apply_button(cancel_btn, 16)
|
||||
buttons.add_child(cancel_btn)
|
||||
cancel_button = Button.new()
|
||||
cancel_button.text = Strings.lookup("ui.radio_cancel")
|
||||
cancel_button.pressed.connect(func(): cancelled.emit())
|
||||
UiStyles.apply_button(cancel_button, 16)
|
||||
buttons.add_child(cancel_button)
|
||||
_focus_controls = [location_edit, desc_edit, weapons_check, danger_option,
|
||||
action_button, cancel_button]
|
||||
UiFocus.link(_focus_controls, false)
|
||||
|
||||
var _title_label: Label
|
||||
|
||||
@@ -148,6 +154,8 @@ func open(controller: Object, emergency: bool, truth: Dictionary) -> void:
|
||||
_holding = false
|
||||
_hold_time = 0.0
|
||||
visible = true
|
||||
UiFocus.link(_focus_controls, false)
|
||||
action_button.grab_focus()
|
||||
|
||||
## Non-emergency requests are a normal click. Emergency calls require the
|
||||
## press-and-hold path, so the click release must not submit early.
|
||||
@@ -200,3 +208,10 @@ func _danger_name(level: int) -> String:
|
||||
2: return "elevated"
|
||||
3: return "immediate threat"
|
||||
_: return "unknown"
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if not visible:
|
||||
return
|
||||
if event.is_action_pressed("ui_cancel"):
|
||||
cancelled.emit()
|
||||
get_viewport().set_input_as_handled()
|
||||
Reference in new issue
Block a user