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
+39
-20
@@ -5,6 +5,7 @@ extends CanvasLayer
|
||||
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")
|
||||
|
||||
signal restart_requested()
|
||||
signal continue_requested()
|
||||
@@ -16,6 +17,9 @@ var _review: Dictionary = {}
|
||||
var report_label: Label
|
||||
var _campaign_label: Label = null
|
||||
var _continue_button: Button = null
|
||||
var _timeline_button: Button = null
|
||||
var _restart_button: Button = null
|
||||
var _quit_button: Button = null
|
||||
|
||||
func _init() -> void:
|
||||
name = "ShiftReview"
|
||||
@@ -56,33 +60,36 @@ func _init() -> void:
|
||||
center.add_child(_campaign_label)
|
||||
|
||||
_continue_button = Button.new()
|
||||
_continue_button.name = "ContinueButton"
|
||||
_continue_button.text = Strings.lookup("review.continue_campaign")
|
||||
_continue_button.pressed.connect(func(): continue_requested.emit())
|
||||
_continue_button.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
center.add_child(_continue_button)
|
||||
|
||||
var timeline := Button.new()
|
||||
timeline.name = "TimelineButton"
|
||||
timeline.text = Strings.lookup("review.timeline_button")
|
||||
timeline.pressed.connect(func(): timeline_requested.emit(_review))
|
||||
timeline.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
center.add_child(timeline)
|
||||
_timeline_button = Button.new()
|
||||
_timeline_button.name = "TimelineButton"
|
||||
_timeline_button.text = Strings.lookup("review.timeline_button")
|
||||
_timeline_button.pressed.connect(func(): timeline_requested.emit(_review))
|
||||
_timeline_button.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
center.add_child(_timeline_button)
|
||||
|
||||
var restart := Button.new()
|
||||
restart.text = Strings.lookup("ui.review_return_menu")
|
||||
restart.pressed.connect(func(): restart_requested.emit())
|
||||
restart.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
center.add_child(restart)
|
||||
_restart_button = Button.new()
|
||||
_restart_button.name = "ReturnMenuButton"
|
||||
_restart_button.text = Strings.lookup("ui.review_return_menu")
|
||||
_restart_button.pressed.connect(func(): restart_requested.emit())
|
||||
_restart_button.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
center.add_child(_restart_button)
|
||||
|
||||
var quit_btn := Button.new()
|
||||
quit_btn.text = Strings.lookup("ui.quit_game")
|
||||
quit_btn.pressed.connect(func(): get_tree().quit())
|
||||
quit_btn.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
_style_review_button(timeline)
|
||||
_quit_button = Button.new()
|
||||
_quit_button.name = "QuitButton"
|
||||
_quit_button.text = Strings.lookup("ui.quit_game")
|
||||
_quit_button.pressed.connect(func(): get_tree().quit())
|
||||
_quit_button.size_flags_horizontal = Control.SIZE_SHRINK_CENTER
|
||||
_style_review_button(_timeline_button)
|
||||
_style_review_button(_continue_button)
|
||||
_style_review_button(restart)
|
||||
_style_review_button(quit_btn)
|
||||
center.add_child(quit_btn)
|
||||
_style_review_button(_restart_button)
|
||||
_style_review_button(_quit_button)
|
||||
center.add_child(_quit_button)
|
||||
|
||||
func _style_review_button(button: Button) -> void:
|
||||
button.custom_minimum_size = Vector2(300, 52)
|
||||
@@ -154,4 +161,16 @@ func show_review(review: Dictionary, scenario: Resource, history: Array = [],
|
||||
_campaign_label.text = ""
|
||||
if _continue_button:
|
||||
_continue_button.visible = not campaign_complete and next_venue != ""
|
||||
visible = true
|
||||
visible = true
|
||||
var buttons: Array = [_continue_button, _timeline_button, _restart_button, _quit_button]
|
||||
UiFocus.link(buttons)
|
||||
var first := UiFocus.first_enabled(buttons)
|
||||
if first:
|
||||
first.grab_focus()
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if not visible:
|
||||
return
|
||||
if event.is_action_pressed("ui_cancel"):
|
||||
restart_requested.emit()
|
||||
get_viewport().set_input_as_handled()
|
||||
Reference in new issue
Block a user