forked from woofmeow/straywild
129 lines
3.5 KiB
GDScript3
129 lines
3.5 KiB
GDScript3
|
|
class_name FileDialogController
|
||
|
|
extends Node
|
||
|
|
|
||
|
|
const FileDialogControllerNavigationType = preload(
|
||
|
|
"res://ui/file_dialog_controller_navigation.gd"
|
||
|
|
)
|
||
|
|
|
||
|
|
var _text_entry_request: Callable
|
||
|
|
var _text_entry_is_open: Callable
|
||
|
|
var _tracked_dialogs: Dictionary[int, WeakRef] = {}
|
||
|
|
|
||
|
|
|
||
|
|
func setup_text_entry(
|
||
|
|
request: Callable,
|
||
|
|
is_open: Callable = Callable(),
|
||
|
|
) -> void:
|
||
|
|
_text_entry_request = request
|
||
|
|
_text_entry_is_open = is_open
|
||
|
|
|
||
|
|
|
||
|
|
func track_dialog(dialog: FileDialog) -> void:
|
||
|
|
if dialog != null:
|
||
|
|
_tracked_dialogs[dialog.get_instance_id()] = weakref(dialog)
|
||
|
|
|
||
|
|
|
||
|
|
func _process(_delta: float) -> void:
|
||
|
|
if _text_entry_is_active():
|
||
|
|
return
|
||
|
|
for instance_id: int in _tracked_dialogs.keys():
|
||
|
|
var reference: WeakRef = _tracked_dialogs[instance_id]
|
||
|
|
var dialog := reference.get_ref() as FileDialog
|
||
|
|
if dialog == null or not is_instance_valid(dialog):
|
||
|
|
_tracked_dialogs.erase(instance_id)
|
||
|
|
continue
|
||
|
|
if not dialog.visible:
|
||
|
|
continue
|
||
|
|
FileDialogControllerNavigationType.configure(dialog)
|
||
|
|
_connect_text_controls(dialog)
|
||
|
|
|
||
|
|
|
||
|
|
func _input(event: InputEvent) -> void:
|
||
|
|
if _text_entry_is_active():
|
||
|
|
return
|
||
|
|
if not (event is InputEventJoypadButton or event is InputEventJoypadMotion):
|
||
|
|
return
|
||
|
|
var scope: Window = _active_scope()
|
||
|
|
if scope == null:
|
||
|
|
return
|
||
|
|
var focused: Control = scope.gui_get_focus_owner()
|
||
|
|
if focused == null:
|
||
|
|
return
|
||
|
|
var direction: Vector2 = _controller_direction(event)
|
||
|
|
var item_list := focused as ItemList
|
||
|
|
if (
|
||
|
|
item_list != null
|
||
|
|
and direction != Vector2.ZERO
|
||
|
|
and FileDialogControllerNavigationType.move_from_item_list(
|
||
|
|
item_list, direction
|
||
|
|
)
|
||
|
|
):
|
||
|
|
get_viewport().set_input_as_handled()
|
||
|
|
return
|
||
|
|
var button_event := event as InputEventJoypadButton
|
||
|
|
if (
|
||
|
|
button_event != null
|
||
|
|
and button_event.pressed
|
||
|
|
and event.is_action_pressed(&"ui_accept")
|
||
|
|
and (focused is LineEdit or focused is TextEdit)
|
||
|
|
and _text_entry_request.is_valid()
|
||
|
|
and bool(_text_entry_request.call(focused))
|
||
|
|
):
|
||
|
|
get_viewport().set_input_as_handled()
|
||
|
|
|
||
|
|
|
||
|
|
func _active_scope() -> Window:
|
||
|
|
for reference_value: WeakRef in _tracked_dialogs.values():
|
||
|
|
var dialog := reference_value.get_ref() as FileDialog
|
||
|
|
if dialog == null or not is_instance_valid(dialog) or not dialog.visible:
|
||
|
|
continue
|
||
|
|
return FileDialogControllerNavigationType.active_scope(dialog)
|
||
|
|
return null
|
||
|
|
|
||
|
|
|
||
|
|
func _controller_direction(event: InputEvent) -> Vector2:
|
||
|
|
if event.is_action_pressed(&"ui_up"):
|
||
|
|
return Vector2.UP
|
||
|
|
if event.is_action_pressed(&"ui_down"):
|
||
|
|
return Vector2.DOWN
|
||
|
|
if event.is_action_pressed(&"ui_left"):
|
||
|
|
return Vector2.LEFT
|
||
|
|
if event.is_action_pressed(&"ui_right"):
|
||
|
|
return Vector2.RIGHT
|
||
|
|
return Vector2.ZERO
|
||
|
|
|
||
|
|
|
||
|
|
func _connect_text_controls(dialog: FileDialog) -> void:
|
||
|
|
var scope: Window = FileDialogControllerNavigationType.active_scope(dialog)
|
||
|
|
for control: Control in (
|
||
|
|
FileDialogControllerNavigationType.interactive_controls(scope)
|
||
|
|
):
|
||
|
|
if not (control is LineEdit or control is TextEdit):
|
||
|
|
continue
|
||
|
|
var callback := _on_text_gui_input.bind(control)
|
||
|
|
if not control.gui_input.is_connected(callback):
|
||
|
|
control.gui_input.connect(callback)
|
||
|
|
|
||
|
|
|
||
|
|
func _on_text_gui_input(event: InputEvent, control: Control) -> void:
|
||
|
|
var button_event := event as InputEventJoypadButton
|
||
|
|
if (
|
||
|
|
button_event == null
|
||
|
|
or not button_event.pressed
|
||
|
|
or (
|
||
|
|
button_event.button_index != JOY_BUTTON_A
|
||
|
|
and not event.is_action_pressed(&"ui_accept")
|
||
|
|
)
|
||
|
|
or not _text_entry_request.is_valid()
|
||
|
|
):
|
||
|
|
return
|
||
|
|
if bool(_text_entry_request.call(control)):
|
||
|
|
control.accept_event()
|
||
|
|
|
||
|
|
|
||
|
|
func _text_entry_is_active() -> bool:
|
||
|
|
return (
|
||
|
|
_text_entry_is_open.is_valid()
|
||
|
|
and bool(_text_entry_is_open.call())
|
||
|
|
)
|