89 lines
2.4 KiB
GDScript3
89 lines
2.4 KiB
GDScript3
|
|
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)
|