forked from woofmeow/straywild
fix: stabilize controller menu navigation
This commit is contained in:
parent
5df8b2e7cc
commit
a8be597d27
32 changed files with 910 additions and 2376 deletions
128
ui/file_dialog_controller.gd
Normal file
128
ui/file_dialog_controller.gd
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
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())
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue