feat: complete controller-first menu navigation
This commit is contained in:
parent
26c9308fcf
commit
4ac7d5edb8
35 changed files with 2013 additions and 85 deletions
88
tests/controller_focus_recovery_validation.gd
Normal file
88
tests/controller_focus_recovery_validation.gd
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
extends SceneTree
|
||||
|
||||
const ControllerFocusRecoveryType = preload(
|
||||
"res://ui/controller_focus_recovery.gd"
|
||||
)
|
||||
|
||||
var _failures: Array[String] = []
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
_run.call_deferred()
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var stage := Control.new()
|
||||
stage.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
root.add_child(stage)
|
||||
var recovery := ControllerFocusRecoveryType.new()
|
||||
stage.add_child(recovery)
|
||||
var option_list := VBoxContainer.new()
|
||||
option_list.position = Vector2(100.0, 100.0)
|
||||
stage.add_child(option_list)
|
||||
var original := _make_button("cute", "cute (show variants)")
|
||||
option_list.add_child(original)
|
||||
await process_frame
|
||||
|
||||
var controller_event := InputEventJoypadButton.new()
|
||||
controller_event.button_index = JOY_BUTTON_A
|
||||
controller_event.pressed = true
|
||||
recovery._input(controller_event)
|
||||
original.grab_focus()
|
||||
await process_frame
|
||||
_expect(root.gui_get_focus_owner() == original, "original option receives focus")
|
||||
|
||||
option_list.remove_child(original)
|
||||
original.queue_free()
|
||||
var replacement := _make_button("cute", "cute (hide variants)")
|
||||
option_list.add_child(replacement)
|
||||
await process_frame
|
||||
await process_frame
|
||||
_expect(
|
||||
root.gui_get_focus_owner() == replacement,
|
||||
"focus follows a rebuilt semantic option",
|
||||
)
|
||||
|
||||
var explicit_target := _make_button("explicit", "explicit")
|
||||
option_list.add_child(explicit_target)
|
||||
option_list.remove_child(replacement)
|
||||
replacement.queue_free()
|
||||
explicit_target.grab_focus()
|
||||
await process_frame
|
||||
_expect(
|
||||
root.gui_get_focus_owner() == explicit_target,
|
||||
"explicit focus changes take precedence over recovery",
|
||||
)
|
||||
var leave_world_ui_event := InputEventJoypadButton.new()
|
||||
leave_world_ui_event.button_index = JOY_BUTTON_LEFT_SHOULDER
|
||||
leave_world_ui_event.pressed = true
|
||||
recovery._input(leave_world_ui_event)
|
||||
root.gui_release_focus()
|
||||
await process_frame
|
||||
await process_frame
|
||||
_expect(
|
||||
root.gui_get_focus_owner() == null,
|
||||
"LB intentionally leaving world UI is never recovered",
|
||||
)
|
||||
|
||||
stage.queue_free()
|
||||
if _failures.is_empty():
|
||||
print("Controller focus recovery validation: PASS")
|
||||
quit(0)
|
||||
return
|
||||
for failure: String in _failures:
|
||||
push_error(failure)
|
||||
quit(1)
|
||||
|
||||
|
||||
func _make_button(text: String, tooltip: String) -> Button:
|
||||
var button := Button.new()
|
||||
button.text = text
|
||||
button.tooltip_text = tooltip
|
||||
button.custom_minimum_size = Vector2(120.0, 48.0)
|
||||
return button
|
||||
|
||||
|
||||
func _expect(condition: bool, message: String) -> void:
|
||||
if not condition:
|
||||
_failures.append(message)
|
||||
Loading…
Add table
Add a link
Reference in a new issue