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
@@ -43,6 +43,7 @@ func test_gamepad_bindings_are_added_once() -> bool:
|
||||
if InputMap.action_get_deadzone(action) > 0.25:
|
||||
problems.append("%s deadzone too high" % action)
|
||||
var buttons := {"action_menu": JOY_BUTTON_A, "cancel": JOY_BUTTON_B,
|
||||
"ui_accept": JOY_BUTTON_A, "ui_cancel": JOY_BUTTON_B,
|
||||
"inspect": JOY_BUTTON_X, "walk_slow": JOY_BUTTON_LEFT_SHOULDER}
|
||||
for action in buttons.keys():
|
||||
var found := false
|
||||
|
||||
@@ -34,16 +34,19 @@ func test_start_menu_emits_selected_venue() -> bool:
|
||||
menu.free()
|
||||
return a and b
|
||||
|
||||
func test_start_menu_clamps_focus() -> bool:
|
||||
func test_start_menu_wraps_focus() -> bool:
|
||||
var menu: Node = StartMenu.new()
|
||||
menu._build()
|
||||
menu._focus_index(-5)
|
||||
var targets: Array = menu._focus_targets
|
||||
menu._focus_index(-1)
|
||||
var low: int = menu._index
|
||||
menu._focus_index(99)
|
||||
menu._focus_index(targets.size())
|
||||
var high: int = menu._index
|
||||
menu.free()
|
||||
return TestUtils.check_eq(low, 0, "focus clamps at the top") \
|
||||
and TestUtils.check_eq(high, StartMenu.VENUES.size() - 1, "focus clamps at the bottom")
|
||||
return TestUtils.check_eq(low, targets.size() - 1, "focus wraps from the top to the bottom") \
|
||||
and TestUtils.check_eq(high, 0, "focus wraps from the bottom to the top") \
|
||||
and TestUtils.check(targets.size() > StartMenu.VENUES.size(),
|
||||
"Continue and footer actions are in the keyboard focus ring")
|
||||
|
||||
func test_pause_overlay_buttons_emit() -> bool:
|
||||
var overlay: Node = PauseOverlay.new()
|
||||
|
||||
@@ -4,6 +4,7 @@ extends RefCounted
|
||||
## theme when a control is focused or disabled.
|
||||
|
||||
const UiStyles := preload("res://src/game/ui/ui_styles.gd")
|
||||
const UiFocus := preload("res://src/game/ui/ui_focus.gd")
|
||||
|
||||
func test_shared_button_states_are_complete() -> bool:
|
||||
var button := Button.new()
|
||||
@@ -24,3 +25,16 @@ func test_shared_button_states_are_complete() -> bool:
|
||||
"the disabled state is visually distinct from normal")
|
||||
button.free()
|
||||
return a and b and c
|
||||
|
||||
func test_focus_helper_skips_hidden_and_disabled_controls() -> bool:
|
||||
var hidden := Button.new()
|
||||
hidden.visible = false
|
||||
var disabled := Button.new()
|
||||
disabled.disabled = true
|
||||
var normal := Button.new()
|
||||
var first := UiFocus.first_enabled([hidden, disabled, normal])
|
||||
var a := TestUtils.check_eq(first, normal, "focus skips hidden and disabled controls")
|
||||
hidden.free()
|
||||
disabled.free()
|
||||
normal.free()
|
||||
return a
|
||||
Reference in new issue
Block a user