stick-the-quick/autoload/UI/UI.gd

248 lines
7.0 KiB
GDScript

extends CanvasLayer
@onready var _audio_player := $'AudioStreamPlayer' as AudioStreamPlayer
var _sound_close := (
preload("res://audio/menu_close.ogg") as AudioStream
)
var _sound_confirm := (
preload("res://audio/menu_confirm.ogg") as AudioStream
)
var _sound_open := (
preload("res://audio/menu_open.ogg") as AudioStream
)
var _sound_select := (
preload("res://audio/menu_select.ogg") as AudioStream
)
class StackFrame:
var node: Control
var args: Dictionary
var _stack: Array[StackFrame]
var _viewport: Viewport
signal returned(value: Variant)
func _push(scene: PackedScene, args: Dictionary = {}) -> bool:
var node := scene.instantiate()
_link_up_buttons_to_audio(node)
if node is Control:
if args.has(&'ui_borrow_instead_of_pausing'):
PlayerControl.borrow()
else:
PlayerControl.pause()
if not _stack.is_empty():
var previous := _stack[_stack.size() - 1]
if node is Notice:
previous.node.process_mode = PROCESS_MODE_DISABLED
else:
remove_child(previous.node)
node.process_mode = PROCESS_MODE_ALWAYS
var frame := StackFrame.new()
frame.node = node
frame.args = args
_stack.push_back(frame)
add_child(node)
var focus := node.find_next_valid_focus() as Control
if focus: focus.grab_focus.call_deferred()
if args.has(&'ui_open_sound_override'):
_audio_player.stream = args.ui_open_sound_override
else:
_audio_player.stream = _sound_open
if _audio_player.stream:
_audio_player.play()
return true
else:
node.queue_free()
push_error("UI._push() called on non-Control PackedScene %s" % node)
return false
func _pop() -> bool:
if _stack.is_empty():
push_error("UI._pop() called with empty stack")
return false
else:
var frame := _stack[_stack.size() - 1]
_stack.pop_back()
remove_child(frame.node)
frame.node.queue_free()
if frame.args.has(&'ui_borrow_instead_of_pausing'):
PlayerControl.restore()
else:
PlayerControl.unpause()
if not _stack.is_empty():
var previous := _stack[_stack.size() - 1]
if frame.node is Notice:
previous.node.process_mode = PROCESS_MODE_INHERIT
else:
if not previous.node.get_parent():
add_child(previous.node)
if frame.args.has(&'ui_close_sound_override'):
_audio_player.stream = frame.args.ui_close_sound_override
else:
_audio_player.stream = _sound_close
if _audio_player.stream:
_audio_player.play()
return true
func Call(scene: PackedScene, args: Dictionary = {}) -> Variant:
var caller_depth: int = _stack.size()
if _push(scene, args):
var _retval: Variant
while _stack.size() != caller_depth:
_retval = await returned
return _retval
else:
return null
func Return(whom: Control = null, what: Variant = null) -> bool:
if _stack.is_empty():
push_error(
"UI.Return() called with empty stack (whom: %s; what: %s)" % [
whom, what
]
)
return false
elif whom and (_stack[_stack.size() - 1].node != whom):
push_error("UI.Return() called with wrong whom (%s) (what: %s)" % [
whom, what
])
return false
elif _pop():
returned.emit(what)
return true
else:
return false
func Args(whom: Control = null) -> Dictionary:
if _stack.is_empty():
push_error("UI.Args() called with empty stack (whom: %s)" % whom)
return {}
else:
var frame := _stack[_stack.size() - 1]
if (frame.node == whom) or not whom:
return frame.args
else:
push_error("UI.Args() called with wrong whom (%s)" % whom)
return {}
func context() -> Control:
return null if _stack.is_empty() else _stack[_stack.size() - 1].node
func _process(_delta: float) -> void:
if not _stack.is_empty():
var frame := _stack[_stack.size() - 1]
if (
(not frame.args.has(&'no_autofocus')) or
(not frame.args.no_autofocus)
):
var focus := get_viewport().gui_get_focus_owner()
if not focus:
focus = frame.node.find_next_valid_focus()
if focus:
focus.grab_focus()
func _input(event: InputEvent) -> void:
var frame: StackFrame = null
if not _stack.is_empty():
frame = _stack[_stack.size() - 1]
var focus := get_viewport().gui_get_focus_owner()
if frame and event.is_action_released(&'pause') and (
frame.args.has(&'on_confirm') or
not frame.args.get(&'no_dismiss', false)
):
if frame.args.has(&'on_confirm'):
frame.args.on_confirm.call()
if not frame.args.get(&'no_dismiss', false):
Return(null, true)
get_viewport().set_input_as_handled()
elif frame and event.is_action_released(&'cancel') and (
frame.args.has(&'on_cancel') or
not frame.args.get(&'no_dismiss', false)
):
if frame.args.has(&'on_cancel'):
frame.args.on_cancel.call()
if not frame.args.get(&'no_dismiss', false):
Return(null, true)
get_viewport().set_input_as_handled()
elif event.is_action_released(&'confirm'):
if focus is BaseButton:
get_viewport().set_input_as_handled()
var press := InputEventAction.new()
press.action = &'ui_accept'
press.pressed = true
var release := InputEventAction.new()
release.action = &'ui_accept'
release.pressed = false
Input.parse_input_event(press)
Input.call_deferred(&'parse_input_event', release)
func say(message: Variant, options: Dictionary = {}) -> Variant:
if message is Array:
var retval: Variant
var leadup_options := options.duplicate()
if leadup_options.has(&'choices'):
leadup_options.erase(&'choices')
for i in message.size():
retval = await say(
message[i],
options if i == message.size() - 1 else leadup_options
)
return retval
else:
options = options.duplicate()
options[&'message'] = message
options[&'ui_borrow_instead_of_pausing'] = true
options[&'no_dismiss'] = true
options[&'ui_open_sound_override'] = null
options[&'ui_close_sound_override'] = null
options[&'ui_confirm_sound_override'] = null
options[&'ui_select_sound_override'] = null
return await Call(
preload('res://ui/Conversation/ConversationUI.tscn'),
options
)
func _play_sound_confirm() -> void:
var frame: StackFrame = null
if not _stack.is_empty():
frame = _stack[_stack.size() - 1]
if frame and frame.args.has(&'ui_confirm_sound_override'):
_audio_player.stream = frame.args.ui_confirm_sound_override
else:
_audio_player.stream = _sound_confirm
if _audio_player.stream:
_audio_player.play()
func _play_sound_select(_dont_care) -> void:
if not _audio_player.playing:
var frame: StackFrame = null
if not _stack.is_empty():
frame = _stack[_stack.size() - 1]
if frame and frame.args.has(&'ui_select_sound_override'):
_audio_player.stream = frame.args.ui_select_sound_override
else:
_audio_player.stream = _sound_select
if _audio_player.stream:
_audio_player.play()
func _link_up_buttons_to_audio(what: Node) -> void:
if what is BaseButton:
what.pressed.connect(_play_sound_confirm)
for child in what.get_children():
_link_up_buttons_to_audio(child)
func _link_up_viewport_to_audio() -> void:
_viewport.gui_focus_changed.connect(_play_sound_select)
func _unlink_viewport_from_audio() -> void:
_viewport.gui_focus_changed.disconnect(_play_sound_select)
func _enter_tree() -> void:
_viewport = get_viewport()
_link_up_viewport_to_audio()
func _exit_tree() -> void:
_unlink_viewport_from_audio()
_viewport = null