extends SceneTree const FileDialogControllerNavigationType = preload( "res://ui/file_dialog_controller_navigation.gd" ) const InterfaceFontControllerType = preload( "res://ui/interface_font_controller.gd" ) const OnScreenKeyboardType = preload("res://ui/on_screen_keyboard.gd") func _initialize() -> void: call_deferred("_run") func _run() -> void: root.size = Vector2i(1280, 720) var dialog := FileDialog.new() dialog.file_mode = FileDialog.FILE_MODE_OPEN_DIR dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.use_native_dialog = false root.add_child(dialog) dialog.current_dir = "/tmp" dialog.popup_centered(Vector2i(900, 540)) for _frame: int in 3: await process_frame FileDialogControllerNavigationType.configure(dialog) await process_frame var root_scope: Window = ( FileDialogControllerNavigationType.active_scope(dialog) ) assert(root_scope == dialog) var root_controls: Array[Control] = ( FileDialogControllerNavigationType.interactive_controls(root_scope) ) var directory_list: ItemList 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 for control: Control in root_controls: if ( control is ItemList and control.accessibility_name == "Directories & Files:" ): directory_list = control as ItemList if control is LineEdit and control.accessibility_name == "Path:": path_edit = control as LineEdit var button := control as Button if button != null: 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 assert(directory_list != null) assert(path_edit != null) assert(create_folder_button != null) assert(has_menu_button) assert(has_cancel) assert(has_select) assert(dialog.gui_get_focus_owner() == directory_list) _assert_directionally_reachable(directory_list, root_controls) create_folder_button.pressed.emit() for _frame: int in 3: await process_frame FileDialogControllerNavigationType.configure(dialog) await process_frame var folder_scope: Window = ( FileDialogControllerNavigationType.active_scope(dialog) ) assert(folder_scope != null and folder_scope != dialog) var folder_controls: Array[Control] = ( FileDialogControllerNavigationType.interactive_controls(folder_scope) ) var folder_name_edit: LineEdit var folder_cancel: Button var folder_ok: Button for control: Control in folder_controls: if control is LineEdit: folder_name_edit = control as LineEdit var button := control as Button if button != null and button.text == "Cancel": folder_cancel = button if button != null and button.text == "OK": folder_ok = button assert(folder_name_edit != null) assert(folder_cancel != null) assert(folder_ok != null) assert(folder_scope.gui_get_focus_owner() == folder_name_edit) _assert_directionally_reachable(folder_name_edit, folder_controls) var keyboard := OnScreenKeyboardType.new() root.add_child(keyboard) keyboard.set_enabled(true) folder_name_edit.grab_focus() assert(keyboard.request_for_control(folder_name_edit)) assert(keyboard.is_open()) assert(keyboard.get_parent() == folder_scope) keyboard.call("_close_keyboard", true) var main_source: String = FileAccess.get_file_as_string( "res://main/main.gd" ) assert(main_source.contains("picker_scope != _data_folder_dialog")) assert(main_source.contains("picker_scope.hide()")) assert(main_source.contains("is_controller_text_entry_open()")) dialog.queue_free() keyboard.queue_free() await process_frame await _validate_compact_dialog() print("File dialog controller navigation validation: PASS") quit() func _validate_compact_dialog() -> void: root.size = Vector2i(640, 480) var font_controller := InterfaceFontControllerType.new() root.add_child(font_controller) await process_frame var dialog := FileDialog.new() dialog.file_mode = FileDialog.FILE_MODE_OPEN_DIR dialog.access = FileDialog.ACCESS_FILESYSTEM dialog.use_native_dialog = false root.add_child(dialog) dialog.current_dir = "/tmp" font_controller.popup_file_dialog(dialog) for _frame: int in 4: await process_frame assert(dialog.size.x <= 616 and dialog.size.y <= 456) var scope: Window = FileDialogControllerNavigationType.active_scope(dialog) var controls: Array[Control] = ( FileDialogControllerNavigationType.interactive_controls(scope) ) var directory_list: ItemList for control: Control in controls: if ( control is ItemList and control.accessibility_name == "Directories & Files:" ): directory_list = control as ItemList break assert(directory_list != null) _assert_directionally_reachable(directory_list, controls) dialog.queue_free() font_controller.queue_free() await process_frame func _assert_directionally_reachable( start: Control, controls: Array[Control], ) -> void: var expected: Dictionary[int, bool] = {} for control: Control in controls: expected[control.get_instance_id()] = true var visited: Dictionary[int, bool] = {start.get_instance_id(): true} var pending: Array[Control] = [start] while not pending.is_empty(): var current: Control = pending.pop_front() for path: NodePath in [ current.focus_neighbor_left, current.focus_neighbor_right, current.focus_neighbor_top, current.focus_neighbor_bottom, ]: var neighbor := current.get_node_or_null(path) as Control if ( neighbor == null or not expected.has(neighbor.get_instance_id()) or visited.has(neighbor.get_instance_id()) ): continue visited[neighbor.get_instance_id()] = true pending.append(neighbor) assert(visited.size() == expected.size())