fix controller file dialog navigation

This commit is contained in:
Alexander Sellite 2026-08-15 22:43:29 -04:00
parent 2208977c8d
commit e12ed54ab8
6 changed files with 469 additions and 26 deletions

View file

@ -35,11 +35,19 @@ func _run() -> void:
FileDialogControllerNavigationType.interactive_controls(root_scope)
)
var directory_list: ItemList
var parent_button: Button
var create_folder_button: Button
var path_edit: LineEdit
var has_menu_button: bool = false
var has_cancel: bool = false
var has_select: bool = false
var drive_button: MenuButton
var refresh_button: Button
var favorite_button: Button
var hidden_button: Button
var grid_button: Button
var list_button: Button
var filter_button: Button
var sort_button: MenuButton
var cancel_button: Button
var select_button: Button
for control: Control in root_controls:
if (
control is ItemList
@ -50,22 +58,125 @@ func _run() -> void:
path_edit = control as LineEdit
var button := control as Button
if button != null:
parent_button = (
button
if button.tooltip_text == "Go to parent folder."
else parent_button
)
create_folder_button = (
button
if button.tooltip_text == "Create a new folder."
else create_folder_button
)
has_cancel = has_cancel or button.text == "Cancel"
has_select = has_select or button.text == "Select Current Folder"
has_menu_button = has_menu_button or control is MenuButton
refresh_button = (
button
if button.tooltip_text == "Refresh files."
else refresh_button
)
favorite_button = (
button
if button.tooltip_text == "(Un)favorite current folder."
else favorite_button
)
hidden_button = (
button
if button.tooltip_text == (
"Toggle the visibility of hidden files."
)
else hidden_button
)
grid_button = (
button
if button.tooltip_text == (
"View items as a grid of thumbnails."
)
else grid_button
)
list_button = (
button
if button.tooltip_text == "View items as a list."
else list_button
)
filter_button = (
button
if button.tooltip_text == (
"Toggle the visibility of the filter for file names."
)
else filter_button
)
cancel_button = button if button.text == "Cancel" else cancel_button
select_button = (
button
if button.text == "Select Current Folder"
else select_button
)
var menu := control as MenuButton
if menu != null:
drive_button = menu if menu.accessibility_name == "Drive" else drive_button
sort_button = (
menu if menu.tooltip_text == "Sort files" else sort_button
)
assert(directory_list != null)
assert(parent_button != null)
assert(path_edit != null)
assert(create_folder_button != null)
assert(has_menu_button)
assert(has_cancel)
assert(has_select)
assert(drive_button != null)
assert(refresh_button != null)
assert(favorite_button != null)
assert(hidden_button != null)
assert(grid_button != null)
assert(list_button != null)
assert(filter_button != null)
assert(sort_button != null)
assert(cancel_button != null)
assert(select_button != null)
assert(dialog.gui_get_focus_owner() == directory_list)
_assert_neighbor(path_edit, &"focus_neighbor_left", parent_button)
_assert_neighbor(path_edit, &"focus_neighbor_right", drive_button)
_assert_neighbor(drive_button, &"focus_neighbor_left", path_edit)
_assert_neighbor(refresh_button, &"focus_neighbor_left", drive_button)
_assert_neighbor(favorite_button, &"focus_neighbor_left", refresh_button)
_assert_neighbor(
create_folder_button, &"focus_neighbor_left", favorite_button
)
_assert_neighbor(hidden_button, &"focus_neighbor_right", grid_button)
_assert_neighbor(grid_button, &"focus_neighbor_right", list_button)
_assert_neighbor(list_button, &"focus_neighbor_right", filter_button)
_assert_neighbor(filter_button, &"focus_neighbor_right", sort_button)
_assert_neighbor(sort_button, &"focus_neighbor_top", create_folder_button)
_assert_neighbor(
create_folder_button, &"focus_neighbor_bottom", sort_button
)
_assert_neighbor(directory_list, &"focus_neighbor_top", hidden_button)
_assert_neighbor(directory_list, &"focus_neighbor_bottom", select_button)
_assert_neighbor(cancel_button, &"focus_neighbor_right", select_button)
_assert_neighbor(select_button, &"focus_neighbor_left", cancel_button)
assert(favorite_button.accessibility_name == "favorite current folder")
assert(create_folder_button.accessibility_name == "new folder")
assert(filter_button.accessibility_name == "filter file names")
_assert_directionally_reachable(directory_list, root_controls)
directory_list.clear()
directory_list.add_item("test folder")
directory_list.select(0)
directory_list.grab_focus()
assert(
FileDialogControllerNavigationType.move_from_item_list(
directory_list, Vector2.UP
)
)
assert(dialog.gui_get_focus_owner() == hidden_button)
directory_list.grab_focus()
assert(
FileDialogControllerNavigationType.move_from_item_list(
directory_list, Vector2.DOWN
)
)
assert(dialog.gui_get_focus_owner() == select_button)
assert(FileDialogControllerNavigationType.activate_control(sort_button))
await process_frame
assert(sort_button.get_popup().visible)
sort_button.get_popup().hide()
await process_frame
create_folder_button.pressed.emit()
for _frame: int in 3:
@ -124,7 +235,14 @@ func _validate_compact_dialog() -> void:
root.size = Vector2i(640, 480)
var font_controller := InterfaceFontControllerType.new()
root.add_child(font_controller)
var keyboard := OnScreenKeyboardType.new()
root.add_child(keyboard)
await process_frame
keyboard.set_enabled(false)
font_controller.set_controller_text_entry_request(
Callable(keyboard, "request_for_control"),
Callable(keyboard, "is_open"),
)
var dialog := FileDialog.new()
dialog.file_mode = FileDialog.FILE_MODE_OPEN_DIR
dialog.access = FileDialog.ACCESS_FILESYSTEM
@ -140,17 +258,43 @@ func _validate_compact_dialog() -> void:
FileDialogControllerNavigationType.interactive_controls(scope)
)
var directory_list: ItemList
var path_edit: LineEdit
var select_button: Button
for control: Control in controls:
if (
control is ItemList
and control.accessibility_name == "Directories & Files:"
):
directory_list = control as ItemList
break
if control is LineEdit and control.accessibility_name == "Path:":
path_edit = control as LineEdit
if control is Button and (control as Button).text == (
"Select Current Folder"
):
select_button = control as Button
assert(directory_list != null)
assert(path_edit != null)
assert(select_button != null)
_assert_directionally_reachable(directory_list, controls)
directory_list.clear()
directory_list.add_item("test folder")
directory_list.select(0)
directory_list.grab_focus()
var down_event := InputEventJoypadButton.new()
down_event.button_index = JOY_BUTTON_DPAD_DOWN
down_event.pressed = true
font_controller.call("_input", down_event)
assert(scope.gui_get_focus_owner() == select_button)
path_edit.grab_focus()
var accept_event := InputEventJoypadButton.new()
accept_event.button_index = JOY_BUTTON_A
accept_event.pressed = true
font_controller.call("_input", accept_event)
assert(keyboard.is_open())
keyboard.call("_close_keyboard", true)
dialog.queue_free()
font_controller.queue_free()
keyboard.queue_free()
await process_frame
@ -181,3 +325,13 @@ func _assert_directionally_reachable(
visited[neighbor.get_instance_id()] = true
pending.append(neighbor)
assert(visited.size() == expected.size())
func _assert_neighbor(
origin: Control,
property_name: StringName,
expected: Control,
) -> void:
var neighbor_path: NodePath = origin.get(property_name)
var neighbor := origin.get_node_or_null(neighbor_path) as Control
assert(neighbor == expected)

View file

@ -20,9 +20,18 @@ func _run() -> void:
func _validate_default_and_persistence() -> void:
var defaults := PlayerSettings.new()
assert(not defaults.on_screen_keyboard_enabled)
assert(KeyboardType.should_enable_for_controller(false, false))
assert(not KeyboardType.should_enable_for_controller(false, true))
assert(KeyboardType.should_enable_for_controller(true, true))
assert(
KeyboardType.should_enable_for_controller(false, false, "Linux")
)
assert(
KeyboardType.should_enable_for_controller(false, true, "Linux")
)
assert(
not KeyboardType.should_enable_for_controller(false, true, "Android")
)
assert(
KeyboardType.should_enable_for_controller(true, true, "Android")
)
var manager := SettingsManagerType.new()
root.add_child(manager)
assert(manager.load_settings())
@ -47,12 +56,7 @@ func _validate_keyboard_entry() -> void:
host.add_child(keyboard)
await process_frame
keyboard.set_enabled(false)
assert(
keyboard.is_enabled()
== not DisplayServer.has_feature(
DisplayServer.FEATURE_VIRTUAL_KEYBOARD
)
)
assert(keyboard.is_enabled())
var activate_event := InputEventJoypadButton.new()
activate_event.button_index = JOY_BUTTON_A
activate_event.pressed = true