generated from SGDA/GodotExampleProject
feat: base
This commit is contained in:
176
addons/maaacks_menus_template/base/scripts/app_settings.gd
Normal file
176
addons/maaacks_menus_template/base/scripts/app_settings.gd
Normal file
@ -0,0 +1,176 @@
|
||||
class_name AppSettings
|
||||
extends Node
|
||||
## Interface to read/write general application settings through [Config].
|
||||
|
||||
const INPUT_SECTION = &'InputSettings'
|
||||
const AUDIO_SECTION = &'AudioSettings'
|
||||
const VIDEO_SECTION = &'VideoSettings'
|
||||
const GAME_SECTION = &'GameSettings'
|
||||
const APPLICATION_SECTION = &'ApplicationSettings'
|
||||
const CUSTOM_SECTION = &'CustomSettings'
|
||||
|
||||
const FULLSCREEN_ENABLED = &'FullscreenEnabled'
|
||||
const SCREEN_RESOLUTION = &'ScreenResolution'
|
||||
const MUTE_SETTING = &'Mute'
|
||||
const MASTER_BUS_INDEX = 0
|
||||
const SYSTEM_BUS_NAME_PREFIX = "_"
|
||||
|
||||
# Input
|
||||
static var default_action_events : Dictionary
|
||||
static var initial_bus_volumes : Array
|
||||
|
||||
static func get_config_input_events(action_name : String, default = null) -> Array:
|
||||
return Config.get_config(INPUT_SECTION, action_name, default)
|
||||
|
||||
static func set_config_input_events(action_name : String, inputs : Array) -> void:
|
||||
Config.set_config(INPUT_SECTION, action_name, inputs)
|
||||
|
||||
static func _clear_config_input_events() -> void:
|
||||
Config.erase_section(INPUT_SECTION)
|
||||
|
||||
static func remove_action_input_event(action_name : String, input_event : InputEvent) -> void:
|
||||
InputMap.action_erase_event(action_name, input_event)
|
||||
var action_events : Array[InputEvent] = InputMap.action_get_events(action_name)
|
||||
var config_events : Array = get_config_input_events(action_name, action_events)
|
||||
config_events.erase(input_event)
|
||||
set_config_input_events(action_name, config_events)
|
||||
|
||||
static func set_input_from_config(action_name : String) -> void:
|
||||
var action_events : Array[InputEvent] = InputMap.action_get_events(action_name)
|
||||
var config_events = get_config_input_events(action_name, action_events)
|
||||
if config_events == action_events:
|
||||
return
|
||||
if config_events.is_empty():
|
||||
Config.erase_section_key(INPUT_SECTION, action_name)
|
||||
return
|
||||
InputMap.action_erase_events(action_name)
|
||||
for config_event in config_events:
|
||||
if config_event not in action_events:
|
||||
InputMap.action_add_event(action_name, config_event)
|
||||
|
||||
static func _get_action_names() -> Array[StringName]:
|
||||
return InputMap.get_actions()
|
||||
|
||||
static func _get_custom_action_names() -> Array[StringName]:
|
||||
var callable_filter := func(action_name): return not (action_name.begins_with("ui_") or action_name.begins_with("spatial_editor"))
|
||||
var action_list := _get_action_names()
|
||||
return action_list.filter(callable_filter)
|
||||
|
||||
static func get_action_names(built_in_actions : bool = false) -> Array[StringName]:
|
||||
if built_in_actions:
|
||||
return _get_action_names()
|
||||
else:
|
||||
return _get_custom_action_names()
|
||||
|
||||
static func reset_to_default_inputs() -> void:
|
||||
_clear_config_input_events()
|
||||
for action_name in default_action_events:
|
||||
InputMap.action_erase_events(action_name)
|
||||
var input_events = default_action_events[action_name]
|
||||
for input_event in input_events:
|
||||
InputMap.action_add_event(action_name, input_event)
|
||||
|
||||
static func set_default_inputs() -> void:
|
||||
var action_list : Array[StringName] = _get_action_names()
|
||||
for action_name in action_list:
|
||||
default_action_events[action_name] = InputMap.action_get_events(action_name)
|
||||
|
||||
static func set_inputs_from_config() -> void:
|
||||
var action_list : Array[StringName] = _get_action_names()
|
||||
for action_name in action_list:
|
||||
set_input_from_config(action_name)
|
||||
|
||||
# Audio
|
||||
|
||||
static func get_bus_volume(bus_index : int) -> float:
|
||||
var initial_linear = 1.0
|
||||
if initial_bus_volumes.size() > bus_index:
|
||||
initial_linear = initial_bus_volumes[bus_index]
|
||||
var linear = db_to_linear(AudioServer.get_bus_volume_db(bus_index))
|
||||
linear /= initial_linear
|
||||
return linear
|
||||
|
||||
static func set_bus_volume(bus_index : int, linear : float) -> void:
|
||||
var initial_linear = 1.0
|
||||
if initial_bus_volumes.size() > bus_index:
|
||||
initial_linear = initial_bus_volumes[bus_index]
|
||||
linear *= initial_linear
|
||||
AudioServer.set_bus_volume_db(bus_index, linear_to_db(linear))
|
||||
|
||||
static func is_muted() -> bool:
|
||||
return AudioServer.is_bus_mute(MASTER_BUS_INDEX)
|
||||
|
||||
static func set_mute(mute_flag : bool) -> void:
|
||||
AudioServer.set_bus_mute(MASTER_BUS_INDEX, mute_flag)
|
||||
|
||||
static func get_audio_bus_name(bus_iter : int) -> String:
|
||||
return AudioServer.get_bus_name(bus_iter)
|
||||
|
||||
static func set_audio_from_config() -> void:
|
||||
for bus_iter in AudioServer.bus_count:
|
||||
var bus_key : String = get_audio_bus_name(bus_iter).to_pascal_case()
|
||||
var bus_volume : float = get_bus_volume(bus_iter)
|
||||
initial_bus_volumes.append(bus_volume)
|
||||
bus_volume = Config.get_config(AUDIO_SECTION, bus_key, bus_volume)
|
||||
if is_nan(bus_volume):
|
||||
bus_volume = 1.0
|
||||
Config.set_config(AUDIO_SECTION, bus_key, bus_volume)
|
||||
set_bus_volume(bus_iter, bus_volume)
|
||||
var mute_audio_flag : bool = is_muted()
|
||||
mute_audio_flag = Config.get_config(AUDIO_SECTION, MUTE_SETTING, mute_audio_flag)
|
||||
set_mute(mute_audio_flag)
|
||||
|
||||
# Video
|
||||
|
||||
static func set_fullscreen_enabled(value : bool, window : Window) -> void:
|
||||
window.mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (value) else Window.MODE_WINDOWED
|
||||
|
||||
static func set_resolution(value : Vector2i, window : Window, update_config : bool = true) -> void:
|
||||
if value.x == 0 or value.y == 0:
|
||||
return
|
||||
window.size = value
|
||||
if update_config:
|
||||
Config.set_config(VIDEO_SECTION, SCREEN_RESOLUTION, value)
|
||||
|
||||
static func is_fullscreen(window : Window) -> bool:
|
||||
return (window.mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (window.mode == Window.MODE_FULLSCREEN)
|
||||
|
||||
static func get_resolution(window : Window) -> Vector2i:
|
||||
var current_resolution : Vector2i = window.size
|
||||
return Config.get_config(VIDEO_SECTION, SCREEN_RESOLUTION, current_resolution)
|
||||
|
||||
static func _on_window_size_changed(window: Window) -> void:
|
||||
Config.set_config(VIDEO_SECTION, SCREEN_RESOLUTION, window.size)
|
||||
|
||||
static func set_video_from_config(window : Window) -> void:
|
||||
window.size_changed.connect(_on_window_size_changed.bind(window))
|
||||
var fullscreen_enabled : bool = is_fullscreen(window)
|
||||
fullscreen_enabled = Config.get_config(VIDEO_SECTION, FULLSCREEN_ENABLED, fullscreen_enabled)
|
||||
set_fullscreen_enabled(fullscreen_enabled, window)
|
||||
if not (fullscreen_enabled or OS.has_feature("web")):
|
||||
var current_resolution : Vector2i = get_resolution(window)
|
||||
set_resolution(current_resolution, window)
|
||||
|
||||
static func set_vsync(vsync_mode : DisplayServer.VSyncMode, window : Window = null) -> void:
|
||||
var window_id : int = 0
|
||||
if window:
|
||||
window_id = window.get_window_id()
|
||||
DisplayServer.window_set_vsync_mode(vsync_mode, window_id)
|
||||
|
||||
static func get_vsync(window : Window = null) -> DisplayServer.VSyncMode:
|
||||
var window_id : int = 0
|
||||
if window:
|
||||
window_id = window.get_window_id()
|
||||
var vsync_mode = DisplayServer.window_get_vsync_mode(window_id)
|
||||
return vsync_mode
|
||||
|
||||
# All
|
||||
|
||||
static func set_from_config() -> void:
|
||||
set_default_inputs()
|
||||
set_inputs_from_config()
|
||||
set_audio_from_config()
|
||||
|
||||
static func set_from_config_and_window(window : Window) -> void:
|
||||
set_from_config()
|
||||
set_video_from_config(window)
|
@ -0,0 +1 @@
|
||||
uid://dwflyh7g2rjxt
|
65
addons/maaacks_menus_template/base/scripts/capture_focus.gd
Normal file
65
addons/maaacks_menus_template/base/scripts/capture_focus.gd
Normal file
@ -0,0 +1,65 @@
|
||||
class_name CaptureFocus
|
||||
extends Control
|
||||
## Node that captures UI focus for games with a hidden mouse or joypad enabled.
|
||||
##
|
||||
## This script assists with capturing UI focus when
|
||||
## opening, closing, or switching between menus.
|
||||
## When attached to a node, it will check if it was changed to visible
|
||||
## and if it should grab focus. If both are true, it will capture focus
|
||||
## on the first eligible node in its scene tree.
|
||||
|
||||
## Hierarchical depth to search in the scene tree.
|
||||
@export var search_depth : int = 1
|
||||
@export var enabled : bool = false
|
||||
@export var null_focus_enabled : bool = true
|
||||
@export var joypad_enabled : bool = true
|
||||
@export var mouse_hidden_enabled : bool = true
|
||||
|
||||
## Locks focus
|
||||
@export var lock : bool = false :
|
||||
set(value):
|
||||
var value_changed : bool = lock != value
|
||||
lock = value
|
||||
if value_changed and not lock:
|
||||
update_focus()
|
||||
|
||||
func _focus_first_search(control_node : Control, levels : int = 1) -> bool:
|
||||
if control_node == null or !control_node.is_visible_in_tree():
|
||||
return false
|
||||
if control_node.focus_mode == FOCUS_ALL:
|
||||
control_node.grab_focus()
|
||||
if control_node is ItemList:
|
||||
control_node.select(0)
|
||||
return true
|
||||
if levels < 1:
|
||||
return false
|
||||
var children = control_node.get_children()
|
||||
for child in children:
|
||||
if _focus_first_search(child, levels - 1):
|
||||
return true
|
||||
return false
|
||||
|
||||
func focus_first() -> void:
|
||||
_focus_first_search(self, search_depth)
|
||||
|
||||
func update_focus() -> void:
|
||||
if lock : return
|
||||
if _is_visible_and_should_capture():
|
||||
focus_first()
|
||||
|
||||
func _should_capture_focus() -> bool:
|
||||
return enabled or \
|
||||
(get_viewport().gui_get_focus_owner() == null and null_focus_enabled) or \
|
||||
(Input.get_connected_joypads().size() > 0 and joypad_enabled) or \
|
||||
(Input.mouse_mode not in [Input.MOUSE_MODE_VISIBLE, Input.MOUSE_MODE_CONFINED] and mouse_hidden_enabled)
|
||||
|
||||
func _is_visible_and_should_capture() -> bool:
|
||||
return is_visible_in_tree() and _should_capture_focus()
|
||||
|
||||
func _on_visibility_changed() -> void:
|
||||
call_deferred("update_focus")
|
||||
|
||||
func _ready() -> void:
|
||||
if is_inside_tree():
|
||||
update_focus()
|
||||
connect("visibility_changed", _on_visibility_changed)
|
@ -0,0 +1 @@
|
||||
uid://1nf36h0gms3q
|
59
addons/maaacks_menus_template/base/scripts/config.gd
Normal file
59
addons/maaacks_menus_template/base/scripts/config.gd
Normal file
@ -0,0 +1,59 @@
|
||||
class_name Config
|
||||
extends Object
|
||||
|
||||
## Interface for a single configuration file through [ConfigFile].
|
||||
|
||||
const CONFIG_FILE_LOCATION := "user://config.cfg"
|
||||
|
||||
static var config_file : ConfigFile
|
||||
|
||||
static func _init() -> void:
|
||||
load_config_file()
|
||||
|
||||
static func _save_config_file() -> void:
|
||||
var save_error : int = config_file.save(CONFIG_FILE_LOCATION)
|
||||
if save_error:
|
||||
push_error("save config file failed with error %d" % save_error)
|
||||
|
||||
static func load_config_file() -> void:
|
||||
if config_file != null:
|
||||
return
|
||||
config_file = ConfigFile.new()
|
||||
var load_error : int = config_file.load(CONFIG_FILE_LOCATION)
|
||||
if load_error:
|
||||
var save_error : int = config_file.save(CONFIG_FILE_LOCATION)
|
||||
if save_error:
|
||||
push_error("save config file failed with error %d" % save_error)
|
||||
|
||||
static func set_config(section: String, key: String, value) -> void:
|
||||
load_config_file()
|
||||
config_file.set_value(section, key, value)
|
||||
_save_config_file()
|
||||
|
||||
static func get_config(section: String, key: String, default = null) -> Variant:
|
||||
load_config_file()
|
||||
return config_file.get_value(section, key, default)
|
||||
|
||||
static func has_section(section: String) -> bool:
|
||||
load_config_file()
|
||||
return config_file.has_section(section)
|
||||
|
||||
static func has_section_key(section: String, key: String) -> bool:
|
||||
load_config_file()
|
||||
return config_file.has_section_key(section, key)
|
||||
|
||||
static func erase_section(section: String) -> void:
|
||||
if has_section(section):
|
||||
config_file.erase_section(section)
|
||||
_save_config_file()
|
||||
|
||||
static func erase_section_key(section: String, key: String) -> void:
|
||||
if has_section_key(section, key):
|
||||
config_file.erase_section_key(section, key)
|
||||
_save_config_file()
|
||||
|
||||
static func get_section_keys(section: String) -> PackedStringArray:
|
||||
load_config_file()
|
||||
if config_file.has_section(section):
|
||||
return config_file.get_section_keys(section)
|
||||
return PackedStringArray()
|
1
addons/maaacks_menus_template/base/scripts/config.gd.uid
Normal file
1
addons/maaacks_menus_template/base/scripts/config.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dxjk8pgi7yhtq
|
51
addons/maaacks_menus_template/base/scripts/file_lister.gd
Normal file
51
addons/maaacks_menus_template/base/scripts/file_lister.gd
Normal file
@ -0,0 +1,51 @@
|
||||
@tool
|
||||
extends Node
|
||||
class_name FileLister
|
||||
## Helper class for listing all the scenes in a directory.
|
||||
|
||||
## List of paths to scene files.
|
||||
@export var _refresh_files_action : bool = false :
|
||||
set(value):
|
||||
if value and Engine.is_editor_hint():
|
||||
_refresh_files()
|
||||
# For Godot 4.4
|
||||
# @export_tool_button("Refresh Files") var _refresh_files_action = _refresh_files
|
||||
## Filled in the editor by selecting a directory.
|
||||
@export var files : Array[String]
|
||||
## Fills files with those discovered in directories, and matching constraints.
|
||||
@export_dir var directories : Array[String] :
|
||||
set(value):
|
||||
directories = value
|
||||
_refresh_files()
|
||||
|
||||
@export_group("Constraints")
|
||||
@export var search : String
|
||||
@export var filter : String
|
||||
|
||||
@export_subgroup("Advanced Search")
|
||||
@export var begins_with : String
|
||||
@export var ends_with : String
|
||||
@export var not_begins_with : String
|
||||
@export var not_ends_with : String
|
||||
|
||||
|
||||
func _refresh_files():
|
||||
if not is_inside_tree(): return
|
||||
files.clear()
|
||||
for directory in directories:
|
||||
var dir_access = DirAccess.open(directory)
|
||||
if dir_access:
|
||||
for file in dir_access.get_files():
|
||||
if (not search.is_empty()) and (not file.contains(search)):
|
||||
continue
|
||||
if (not filter.is_empty()) and (file.contains(filter)):
|
||||
continue
|
||||
if (not begins_with.is_empty()) and (not file.begins_with(begins_with)):
|
||||
continue
|
||||
if (not ends_with.is_empty()) and (not file.ends_with(ends_with)):
|
||||
continue
|
||||
if (not not_begins_with.is_empty()) and (file.begins_with(not_begins_with)):
|
||||
continue
|
||||
if (not not_ends_with.is_empty()) and (file.ends_with(not_ends_with)):
|
||||
continue
|
||||
files.append(directory + "/" + file)
|
@ -0,0 +1 @@
|
||||
uid://bij7wsh8d44gv
|
175
addons/maaacks_menus_template/base/scripts/input_helper.gd
Normal file
175
addons/maaacks_menus_template/base/scripts/input_helper.gd
Normal file
@ -0,0 +1,175 @@
|
||||
class_name InputEventHelper
|
||||
extends Node
|
||||
## Helper class for organizing constants related to [InputEvent].
|
||||
|
||||
const DEVICE_KEYBOARD = "Keyboard"
|
||||
const DEVICE_MOUSE = "Mouse"
|
||||
const DEVICE_XBOX_CONTROLLER = "Xbox"
|
||||
const DEVICE_SWITCH_CONTROLLER = "Switch"
|
||||
const DEVICE_SWITCH_JOYCON_LEFT_CONTROLLER = "Switch Left Joycon"
|
||||
const DEVICE_SWITCH_JOYCON_RIGHT_CONTROLLER = "Switch Right Joycon"
|
||||
const DEVICE_SWITCH_JOYCON_COMBINED_CONTROLLER = "Switch Combined Joycons"
|
||||
const DEVICE_PLAYSTATION_CONTROLLER = "Playstation"
|
||||
const DEVICE_STEAMDECK_CONTROLLER = "Steamdeck"
|
||||
const DEVICE_GENERIC = "Generic"
|
||||
|
||||
const JOYSTICK_LEFT_NAME = "Left Stick"
|
||||
const JOYSTICK_RIGHT_NAME = "Right Stick"
|
||||
const D_PAD_NAME = "Dpad"
|
||||
|
||||
const MOUSE_BUTTONS : Array = ["None", "Left", "Right", "Middle", "Scroll Up", "Scroll Down", "Wheel Left", "Wheel Right"]
|
||||
|
||||
const JOYPAD_BUTTON_NAME_MAP : Dictionary = {
|
||||
DEVICE_GENERIC : ["Trigger A", "Trigger B", "Trigger C", "", "", "", "", "Left Stick Press", "Right Stick Press", "Left Shoulder", "Right Shoulder", "Up", "Down", "Left", "Right"],
|
||||
DEVICE_XBOX_CONTROLLER : ["A", "B", "X", "Y", "View", "Home", "Menu", "Left Stick Press", "Right Stick Press", "Left Shoulder", "Right Shoulder", "Up", "Down", "Left", "Right", "Share"],
|
||||
DEVICE_SWITCH_CONTROLLER : ["B", "A", "Y", "X", "Minus", "", "Plus", "Left Stick Press", "Right Stick Press", "Left Shoulder", "Right Shoulder", "Up", "Down", "Left", "Right", "Capture"],
|
||||
DEVICE_PLAYSTATION_CONTROLLER : ["Cross", "Circle", "Square", "Triangle", "Select", "PS", "Options", "Left Stick Press", "Right Stick Press", "Left Shoulder", "Right Shoulder", "Up", "Down", "Left", "Right", "Microphone"],
|
||||
DEVICE_STEAMDECK_CONTROLLER : ["A", "B", "X", "Y", "View", "", "Options", "Left Stick Press", "Right Stick Press", "Left Shoulder", "Right Shoulder", "Up", "Down", "Left", "Right"]
|
||||
} # Dictionary[String, Array]
|
||||
|
||||
const SDL_DEVICE_NAMES: Dictionary = {
|
||||
DEVICE_XBOX_CONTROLLER: ["XInput", "XBox"],
|
||||
DEVICE_PLAYSTATION_CONTROLLER: ["Sony", "PS5", "PS4", "Nacon"],
|
||||
DEVICE_STEAMDECK_CONTROLLER: ["Steam"],
|
||||
DEVICE_SWITCH_CONTROLLER: ["Switch"],
|
||||
DEVICE_SWITCH_JOYCON_LEFT_CONTROLLER: ["Joy-Con (L)", "Left Joy-Con"],
|
||||
DEVICE_SWITCH_JOYCON_RIGHT_CONTROLLER: ["Joy-Con (R)", "Right Joy-Con"],
|
||||
DEVICE_SWITCH_JOYCON_COMBINED_CONTROLLER: ["Joy-Con (L/R)", "Combined Joy-Cons"],
|
||||
}
|
||||
|
||||
const JOY_BUTTON_NAMES : Dictionary = {
|
||||
JOY_BUTTON_A: "Button A",
|
||||
JOY_BUTTON_B: "Button B",
|
||||
JOY_BUTTON_X: "Button X",
|
||||
JOY_BUTTON_Y: "Button Y",
|
||||
JOY_BUTTON_LEFT_SHOULDER: "Left Shoulder",
|
||||
JOY_BUTTON_RIGHT_SHOULDER: "Right Shoulder",
|
||||
JOY_BUTTON_LEFT_STICK: "Left Stick",
|
||||
JOY_BUTTON_RIGHT_STICK: "Right Stick",
|
||||
JOY_BUTTON_START : "Button Start",
|
||||
JOY_BUTTON_GUIDE : "Button Guide",
|
||||
JOY_BUTTON_BACK : "Button Back",
|
||||
JOY_BUTTON_DPAD_UP : D_PAD_NAME + " Up",
|
||||
JOY_BUTTON_DPAD_DOWN : D_PAD_NAME + " Down",
|
||||
JOY_BUTTON_DPAD_LEFT : D_PAD_NAME + " Left",
|
||||
JOY_BUTTON_DPAD_RIGHT : D_PAD_NAME + " Right",
|
||||
JOY_BUTTON_MISC1 : "Misc",
|
||||
}
|
||||
|
||||
const JOYPAD_DPAD_NAMES : Dictionary = {
|
||||
JOY_BUTTON_DPAD_UP : D_PAD_NAME + " Up",
|
||||
JOY_BUTTON_DPAD_DOWN : D_PAD_NAME + " Down",
|
||||
JOY_BUTTON_DPAD_LEFT : D_PAD_NAME + " Left",
|
||||
JOY_BUTTON_DPAD_RIGHT : D_PAD_NAME + " Right",
|
||||
}
|
||||
|
||||
const JOY_AXIS_NAMES : Dictionary = {
|
||||
JOY_AXIS_TRIGGER_LEFT: "Left Trigger",
|
||||
JOY_AXIS_TRIGGER_RIGHT: "Right Trigger",
|
||||
}
|
||||
|
||||
const BUILT_IN_ACTION_NAME_MAP : Dictionary = {
|
||||
"ui_accept" : "Accept",
|
||||
"ui_select" : "Select",
|
||||
"ui_cancel" : "Cancel",
|
||||
"ui_focus_next" : "Focus Next",
|
||||
"ui_focus_prev" : "Focus Prev",
|
||||
"ui_left" : "Left (UI)",
|
||||
"ui_right" : "Right (UI)",
|
||||
"ui_up" : "Up (UI)",
|
||||
"ui_down" : "Down (UI)",
|
||||
"ui_page_up" : "Page Up",
|
||||
"ui_page_down" : "Page Down",
|
||||
"ui_home" : "Home",
|
||||
"ui_end" : "End",
|
||||
"ui_cut" : "Cut",
|
||||
"ui_copy" : "Copy",
|
||||
"ui_paste" : "Paste",
|
||||
"ui_undo" : "Undo",
|
||||
"ui_redo" : "Redo",
|
||||
}
|
||||
|
||||
static func has_joypad() -> bool:
|
||||
return Input.get_connected_joypads().size() > 0
|
||||
|
||||
static func is_joypad_event(event: InputEvent) -> bool:
|
||||
return event is InputEventJoypadButton or event is InputEventJoypadMotion
|
||||
|
||||
static func is_mouse_event(event: InputEvent) -> bool:
|
||||
return event is InputEventMouseButton or event is InputEventMouseMotion
|
||||
|
||||
static func get_device_name_by_id(device_id : int) -> String:
|
||||
if device_id >= 0:
|
||||
var device_name = Input.get_joy_name(device_id)
|
||||
for device_key in SDL_DEVICE_NAMES:
|
||||
for keyword in SDL_DEVICE_NAMES[device_key]:
|
||||
if device_name.containsn(keyword):
|
||||
return device_key
|
||||
return DEVICE_GENERIC
|
||||
|
||||
static func get_device_name(event: InputEvent) -> String:
|
||||
if event is InputEventJoypadButton or event is InputEventJoypadMotion:
|
||||
if event.device == -1:
|
||||
return DEVICE_GENERIC
|
||||
var device_id = event.device
|
||||
return get_device_name_by_id(device_id)
|
||||
return DEVICE_GENERIC
|
||||
|
||||
static func _display_server_supports_keycode_from_physical():
|
||||
return OS.has_feature("windows") or OS.has_feature("macos") or OS.has_feature("linux")
|
||||
|
||||
static func get_text(event : InputEvent) -> String:
|
||||
if event == null:
|
||||
return ""
|
||||
if event is InputEventJoypadButton:
|
||||
if event.button_index in JOY_BUTTON_NAMES:
|
||||
return JOY_BUTTON_NAMES[event.button_index]
|
||||
elif event is InputEventJoypadMotion:
|
||||
var full_string := ""
|
||||
var direction_string := ""
|
||||
var is_right_or_down : bool = event.axis_value > 0.0
|
||||
if event.axis in JOY_AXIS_NAMES:
|
||||
return JOY_AXIS_NAMES[event.axis]
|
||||
match(event.axis):
|
||||
JOY_AXIS_LEFT_X:
|
||||
full_string = JOYSTICK_LEFT_NAME
|
||||
direction_string = "Right" if is_right_or_down else "Left"
|
||||
JOY_AXIS_LEFT_Y:
|
||||
full_string = JOYSTICK_LEFT_NAME
|
||||
direction_string = "Down" if is_right_or_down else "Up"
|
||||
JOY_AXIS_RIGHT_X:
|
||||
full_string = JOYSTICK_RIGHT_NAME
|
||||
direction_string = "Right" if is_right_or_down else "Left"
|
||||
JOY_AXIS_RIGHT_Y:
|
||||
full_string = JOYSTICK_RIGHT_NAME
|
||||
direction_string = "Down" if is_right_or_down else "Up"
|
||||
full_string += " " + direction_string
|
||||
return full_string
|
||||
elif event is InputEventKey:
|
||||
var keycode : Key = event.get_physical_keycode()
|
||||
if keycode:
|
||||
keycode = event.get_physical_keycode_with_modifiers()
|
||||
else:
|
||||
keycode = event.get_keycode_with_modifiers()
|
||||
if _display_server_supports_keycode_from_physical():
|
||||
keycode = DisplayServer.keyboard_get_keycode_from_physical(keycode)
|
||||
return OS.get_keycode_string(keycode)
|
||||
return event.as_text()
|
||||
|
||||
static func get_device_specific_text(event : InputEvent, device_name : String = "") -> String:
|
||||
if device_name.is_empty():
|
||||
device_name = get_device_name(event)
|
||||
if event is InputEventJoypadButton:
|
||||
var joypad_button : String = ""
|
||||
if event.button_index in JOYPAD_DPAD_NAMES:
|
||||
joypad_button = JOYPAD_DPAD_NAMES[event.button_index]
|
||||
elif event.button_index < JOYPAD_BUTTON_NAME_MAP[device_name].size():
|
||||
joypad_button = JOYPAD_BUTTON_NAME_MAP[device_name][event.button_index]
|
||||
return "%s %s" % [device_name, joypad_button]
|
||||
if event is InputEventJoypadMotion:
|
||||
return "%s %s" % [device_name, get_text(event)]
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index < MOUSE_BUTTONS.size():
|
||||
var mouse_button : String = MOUSE_BUTTONS[event.button_index]
|
||||
return "%s %s" % [DEVICE_MOUSE, mouse_button]
|
||||
return get_text(event).capitalize()
|
@ -0,0 +1 @@
|
||||
uid://6xujceamar4h
|
184
addons/maaacks_menus_template/base/scripts/music_controller.gd
Normal file
184
addons/maaacks_menus_template/base/scripts/music_controller.gd
Normal file
@ -0,0 +1,184 @@
|
||||
class_name MusicController
|
||||
extends Node
|
||||
## Controller for music playback across scenes.
|
||||
##
|
||||
## This node persistently checks for stream players added to the scene tree.
|
||||
## It detects stream players that match the audio bus and have autoplay on.
|
||||
## It then reparents the stream players to itself, and handles blending.
|
||||
## The expected use-case is to attach this script to an autoloaded scene.
|
||||
|
||||
const BLEND_BUS_PREFIX : String = "Blend"
|
||||
const MAX_DEPTH = 16
|
||||
const MINIMUM_VOLUME_DB = -80
|
||||
|
||||
## Detect stream players with matching audio bus.
|
||||
@export var audio_bus : StringName = &"Music"
|
||||
|
||||
@export_group("Blending")
|
||||
@export var fade_out_duration : float = 0.0 :
|
||||
set(value):
|
||||
fade_out_duration = value
|
||||
if fade_out_duration < 0:
|
||||
fade_out_duration = 0
|
||||
|
||||
@export var fade_in_duration : float = 0.0 :
|
||||
set(value):
|
||||
fade_in_duration = value
|
||||
if fade_in_duration < 0:
|
||||
fade_in_duration = 0
|
||||
|
||||
## Matched stream players with no stream set will stop current playback.
|
||||
@export var empty_streams_stop_player : bool = true
|
||||
|
||||
var music_stream_player : AudioStreamPlayer
|
||||
var blend_audio_bus : StringName
|
||||
var blend_audio_bus_idx : int
|
||||
|
||||
func fade_out(duration : float = 0.0) -> Tween:
|
||||
if is_zero_approx(duration): return
|
||||
music_stream_player.bus = audio_bus
|
||||
var tween = create_tween()
|
||||
tween.tween_property(music_stream_player, "volume_db", MINIMUM_VOLUME_DB, duration)
|
||||
return tween
|
||||
|
||||
func _set_sub_audio_volume_db(sub_volume_db : float) -> void:
|
||||
AudioServer.set_bus_volume_db(blend_audio_bus_idx, sub_volume_db)
|
||||
|
||||
func fade_in(duration : float = 0.0) -> Tween:
|
||||
if is_zero_approx(duration): return
|
||||
music_stream_player.bus = blend_audio_bus
|
||||
AudioServer.set_bus_volume_db(blend_audio_bus_idx, MINIMUM_VOLUME_DB)
|
||||
var tween = create_tween()
|
||||
tween.tween_method(_set_sub_audio_volume_db, MINIMUM_VOLUME_DB, 0, duration)
|
||||
return tween
|
||||
|
||||
func blend_to(target_volume_db : float, duration : float = 0.0) -> Tween:
|
||||
if not is_zero_approx(duration):
|
||||
var tween = create_tween()
|
||||
tween.tween_property(music_stream_player, "volume_db", target_volume_db, duration)
|
||||
return tween
|
||||
music_stream_player.volume_db = target_volume_db
|
||||
return
|
||||
|
||||
func stop() -> void:
|
||||
if not is_instance_valid(music_stream_player):
|
||||
return
|
||||
music_stream_player.stop()
|
||||
|
||||
func play(playback_position : float = 0.0) -> void:
|
||||
if not is_instance_valid(music_stream_player):
|
||||
return
|
||||
if is_zero_approx(playback_position) and not music_stream_player.playing:
|
||||
music_stream_player.play()
|
||||
else:
|
||||
music_stream_player.play(playback_position)
|
||||
|
||||
func _fade_out_and_free() -> void:
|
||||
if not is_instance_valid(music_stream_player):
|
||||
return
|
||||
var stream_player = music_stream_player
|
||||
var tween = fade_out(fade_out_duration)
|
||||
if tween != null:
|
||||
await(tween.finished)
|
||||
stream_player.queue_free()
|
||||
|
||||
func _play_and_fade_in() -> void:
|
||||
play()
|
||||
fade_in( fade_in_duration )
|
||||
|
||||
func _is_matching_stream(stream_player : AudioStreamPlayer) -> bool:
|
||||
if stream_player.bus != audio_bus:
|
||||
return false
|
||||
if not is_instance_valid(music_stream_player):
|
||||
return false
|
||||
return music_stream_player.stream == stream_player.stream
|
||||
|
||||
func _connect_stream_on_tree_exiting(stream_player : AudioStreamPlayer) -> void:
|
||||
if not stream_player.tree_exiting.is_connected(_on_removed_music_player.bind(stream_player)):
|
||||
stream_player.tree_exiting.connect(_on_removed_music_player.bind(stream_player))
|
||||
|
||||
func _blend_and_remove_stream_player(stream_player : AudioStreamPlayer) -> void:
|
||||
var playback_position := music_stream_player.get_playback_position() + AudioServer.get_time_since_last_mix()
|
||||
var old_stream_player = music_stream_player
|
||||
music_stream_player = stream_player
|
||||
music_stream_player.bus = blend_audio_bus
|
||||
play(playback_position)
|
||||
old_stream_player.stop()
|
||||
old_stream_player.queue_free()
|
||||
_connect_stream_on_tree_exiting(music_stream_player)
|
||||
|
||||
func _blend_and_connect_stream_player(stream_player : AudioStreamPlayer) -> void:
|
||||
stream_player.bus = blend_audio_bus
|
||||
_fade_out_and_free()
|
||||
music_stream_player = stream_player
|
||||
_play_and_fade_in()
|
||||
_connect_stream_on_tree_exiting(music_stream_player)
|
||||
|
||||
func play_stream_player(stream_player : AudioStreamPlayer) -> void:
|
||||
if stream_player == music_stream_player : return
|
||||
if stream_player.stream == null and not empty_streams_stop_player:
|
||||
return
|
||||
if _is_matching_stream(stream_player) :
|
||||
_blend_and_remove_stream_player(stream_player)
|
||||
else:
|
||||
_blend_and_connect_stream_player(stream_player)
|
||||
|
||||
func get_stream_player(audio_stream : AudioStream) -> AudioStreamPlayer:
|
||||
var stream_player := AudioStreamPlayer.new()
|
||||
stream_player.stream = audio_stream
|
||||
stream_player.bus = audio_bus
|
||||
add_child(stream_player)
|
||||
return stream_player
|
||||
|
||||
func play_stream(audio_stream : AudioStream) -> AudioStreamPlayer:
|
||||
var stream_player := get_stream_player(audio_stream)
|
||||
stream_player.play.call_deferred()
|
||||
play_stream_player( stream_player )
|
||||
return stream_player
|
||||
|
||||
func _clone_music_player(stream_player : AudioStreamPlayer) -> void:
|
||||
var playback_position := stream_player.get_playback_position() + AudioServer.get_time_since_last_mix()
|
||||
var audio_stream := stream_player.stream
|
||||
music_stream_player = get_stream_player(audio_stream)
|
||||
music_stream_player.volume_db = stream_player.volume_db
|
||||
music_stream_player.max_polyphony = stream_player.max_polyphony
|
||||
music_stream_player.pitch_scale = stream_player.pitch_scale
|
||||
music_stream_player.play.call_deferred(playback_position)
|
||||
|
||||
func _reparent_music_player(stream_player : AudioStreamPlayer) -> void:
|
||||
var playback_position := stream_player.get_playback_position() + AudioServer.get_time_since_last_mix()
|
||||
stream_player.owner = null
|
||||
stream_player.reparent.call_deferred(self)
|
||||
stream_player.play.call_deferred(playback_position)
|
||||
|
||||
func _node_matches_checks(node : Node) -> bool:
|
||||
return node is AudioStreamPlayer and node.autoplay and node.bus == audio_bus
|
||||
|
||||
func _on_removed_music_player(node: Node) -> void:
|
||||
if music_stream_player == node:
|
||||
if node.owner == null:
|
||||
_clone_music_player(node)
|
||||
else:
|
||||
_reparent_music_player(node)
|
||||
if node.tree_exiting.is_connected(_on_removed_music_player.bind(node)):
|
||||
node.tree_exiting.disconnect(_on_removed_music_player.bind(node))
|
||||
|
||||
func _on_added_music_player(node: Node) -> void:
|
||||
if node == music_stream_player : return
|
||||
if not (_node_matches_checks(node)) : return
|
||||
play_stream_player(node)
|
||||
|
||||
func _enter_tree() -> void:
|
||||
AudioServer.add_bus()
|
||||
blend_audio_bus_idx = AudioServer.bus_count - 1
|
||||
blend_audio_bus = AppSettings.SYSTEM_BUS_NAME_PREFIX + BLEND_BUS_PREFIX + audio_bus
|
||||
AudioServer.set_bus_send(blend_audio_bus_idx, audio_bus)
|
||||
AudioServer.set_bus_name(blend_audio_bus_idx, blend_audio_bus)
|
||||
var tree_node = get_tree()
|
||||
if not tree_node.node_added.is_connected(_on_added_music_player):
|
||||
tree_node.node_added.connect(_on_added_music_player)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
var tree_node = get_tree()
|
||||
if tree_node.node_added.is_connected(_on_added_music_player):
|
||||
tree_node.node_added.disconnect(_on_added_music_player)
|
@ -0,0 +1 @@
|
||||
uid://ctrh4qyxqncss
|
@ -0,0 +1,18 @@
|
||||
class_name PauseMenuController
|
||||
extends Node
|
||||
|
||||
## Node for opening a pause menu when detecting a 'ui_cancel' event.
|
||||
|
||||
@export var pause_menu_packed : PackedScene
|
||||
@export var focused_viewport : Viewport
|
||||
|
||||
func _unhandled_input(event : InputEvent) -> void:
|
||||
if event.is_action_pressed("ui_cancel"):
|
||||
if not focused_viewport:
|
||||
focused_viewport = get_viewport()
|
||||
var _initial_focus_control = focused_viewport.gui_get_focus_owner()
|
||||
var current_menu = pause_menu_packed.instantiate()
|
||||
get_tree().current_scene.call_deferred("add_child", current_menu)
|
||||
await current_menu.tree_exited
|
||||
if is_inside_tree() and _initial_focus_control:
|
||||
_initial_focus_control.grab_focus()
|
@ -0,0 +1 @@
|
||||
uid://cyh0d64pfygbl
|
@ -0,0 +1,207 @@
|
||||
class_name UISoundController
|
||||
extends Node
|
||||
## Controller for managing all UI sounds in a scene from one place.
|
||||
##
|
||||
## This node manages all of the UI sounds under the provided node path.
|
||||
## When attached just below the root node of a scene tree, it will manage
|
||||
## all of the UI sounds in that scene.
|
||||
|
||||
const MAX_DEPTH = 16
|
||||
|
||||
@export var root_path : NodePath = ^".."
|
||||
@export var audio_bus : StringName = &"SFX"
|
||||
## Continually check any new nodes added to the scene tree.
|
||||
@export var persistent : bool = true :
|
||||
set(value):
|
||||
persistent = value
|
||||
_update_persistent_signals()
|
||||
|
||||
@export_group("Button Sounds")
|
||||
@export var button_hovered : AudioStream
|
||||
@export var button_focused : AudioStream
|
||||
@export var button_pressed : AudioStream
|
||||
|
||||
@export_group("TabBar Sounds")
|
||||
@export var tab_hovered : AudioStream
|
||||
@export var tab_changed : AudioStream
|
||||
@export var tab_selected : AudioStream
|
||||
|
||||
@export_group("Slider Sounds")
|
||||
@export var slider_hovered : AudioStream
|
||||
@export var slider_focused : AudioStream
|
||||
@export var slider_drag_started : AudioStream
|
||||
@export var slider_drag_ended : AudioStream
|
||||
|
||||
@export_group("LineEdit Sounds")
|
||||
@export var line_hovered : AudioStream
|
||||
@export var line_focused : AudioStream
|
||||
@export var line_text_changed : AudioStream
|
||||
@export var line_text_submitted : AudioStream
|
||||
@export var line_text_change_rejected : AudioStream
|
||||
|
||||
@export_group("ItemList Sounds")
|
||||
@export var item_list_selected : AudioStream
|
||||
@export var item_list_activated : AudioStream
|
||||
|
||||
@export_group("Tree Sounds")
|
||||
@export var tree_item_selected : AudioStream
|
||||
@export var tree_item_activated : AudioStream
|
||||
@export var tree_button_clicked : AudioStream
|
||||
|
||||
@onready var root_node : Node = get_node(root_path)
|
||||
|
||||
var button_hovered_player : AudioStreamPlayer
|
||||
var button_focused_player : AudioStreamPlayer
|
||||
var button_pressed_player : AudioStreamPlayer
|
||||
|
||||
var tab_hovered_player : AudioStreamPlayer
|
||||
var tab_changed_player : AudioStreamPlayer
|
||||
var tab_selected_player : AudioStreamPlayer
|
||||
|
||||
var slider_hovered_player : AudioStreamPlayer
|
||||
var slider_focused_player : AudioStreamPlayer
|
||||
var slider_drag_started_player : AudioStreamPlayer
|
||||
var slider_drag_ended_player : AudioStreamPlayer
|
||||
|
||||
var line_hovered_player : AudioStreamPlayer
|
||||
var line_focused_player : AudioStreamPlayer
|
||||
var line_text_changed_player : AudioStreamPlayer
|
||||
var line_text_submitted_player : AudioStreamPlayer
|
||||
var line_text_change_rejected_player : AudioStreamPlayer
|
||||
|
||||
var item_list_activated_player : AudioStreamPlayer
|
||||
var item_list_selected_player : AudioStreamPlayer
|
||||
|
||||
var tree_item_activated_player : AudioStreamPlayer
|
||||
var tree_item_selected_player : AudioStreamPlayer
|
||||
var tree_button_clicked_player : AudioStreamPlayer
|
||||
|
||||
func _update_persistent_signals() -> void:
|
||||
if not is_inside_tree():
|
||||
return
|
||||
var tree_node = get_tree()
|
||||
if persistent:
|
||||
if not tree_node.node_added.is_connected(connect_ui_sounds):
|
||||
tree_node.node_added.connect(connect_ui_sounds)
|
||||
else:
|
||||
if tree_node.node_added.is_connected(connect_ui_sounds):
|
||||
tree_node.node_added.disconnect(connect_ui_sounds)
|
||||
|
||||
func _build_stream_player(stream : AudioStream, stream_name : String = "") -> AudioStreamPlayer:
|
||||
var stream_player : AudioStreamPlayer
|
||||
if stream != null:
|
||||
stream_player = AudioStreamPlayer.new()
|
||||
stream_player.stream = stream
|
||||
stream_player.bus = audio_bus
|
||||
stream_player.name = stream_name + "AudioStreamPlayer"
|
||||
add_child(stream_player)
|
||||
return stream_player
|
||||
|
||||
func _build_button_stream_players() -> void:
|
||||
button_hovered_player = _build_stream_player(button_hovered, "ButtonHovered")
|
||||
button_focused_player = _build_stream_player(button_focused, "ButtonFocused")
|
||||
button_pressed_player = _build_stream_player(button_pressed, "ButtonClicked")
|
||||
|
||||
func _build_tab_stream_players() -> void:
|
||||
tab_hovered_player = _build_stream_player(tab_hovered, "TabHovered")
|
||||
tab_changed_player = _build_stream_player(tab_changed, "TabChanged")
|
||||
tab_selected_player = _build_stream_player(tab_selected, "TabSelected")
|
||||
|
||||
func _build_slider_stream_players() -> void:
|
||||
slider_hovered_player = _build_stream_player(slider_hovered, "SliderHovered")
|
||||
slider_focused_player = _build_stream_player(slider_focused, "SliderFocused")
|
||||
slider_drag_started_player = _build_stream_player(slider_drag_started, "SliderDragStarted")
|
||||
slider_drag_ended_player = _build_stream_player(slider_drag_ended, "SliderDragEnded")
|
||||
|
||||
func _build_line_stream_players() -> void:
|
||||
line_hovered_player = _build_stream_player(line_hovered, "LineHovered")
|
||||
line_focused_player = _build_stream_player(line_focused, "LineFocused")
|
||||
line_text_changed_player = _build_stream_player(line_text_changed, "LineTextChanged")
|
||||
line_text_submitted_player = _build_stream_player(line_text_submitted, "LineTextSubmitted")
|
||||
line_text_change_rejected_player = _build_stream_player(line_text_change_rejected, "LineTextChangeRejected")
|
||||
|
||||
func _build_item_list_stream_players() -> void:
|
||||
item_list_activated_player = _build_stream_player(item_list_activated, "ItemActivated")
|
||||
item_list_selected_player = _build_stream_player(item_list_selected, "ItemSelected")
|
||||
|
||||
func _build_tree_stream_players() -> void:
|
||||
tree_item_activated_player = _build_stream_player(tree_item_activated, "TreeItemActivated")
|
||||
tree_item_selected_player = _build_stream_player(tree_item_selected, "TreeItemSelected")
|
||||
tree_button_clicked_player = _build_stream_player(tree_button_clicked, "TreeButtonClicked")
|
||||
|
||||
func _build_all_stream_players() -> void:
|
||||
_build_button_stream_players()
|
||||
_build_tab_stream_players()
|
||||
_build_slider_stream_players()
|
||||
_build_line_stream_players()
|
||||
_build_item_list_stream_players()
|
||||
_build_tree_stream_players()
|
||||
|
||||
func _play_stream(stream_player : AudioStreamPlayer) -> void:
|
||||
if not stream_player.is_inside_tree():
|
||||
return
|
||||
stream_player.play()
|
||||
|
||||
func _tab_event_play_stream(_tab_idx : int, stream_player : AudioStreamPlayer) -> void:
|
||||
_play_stream(stream_player)
|
||||
|
||||
func _slider_drag_ended_play_stream(_value_changed : bool, stream_player : AudioStreamPlayer) -> void:
|
||||
_play_stream(stream_player)
|
||||
|
||||
func _line_event_play_stream(_new_text : String, stream_player : AudioStreamPlayer) -> void:
|
||||
_play_stream(stream_player)
|
||||
|
||||
func _item_list_play_stream(_index : int, stream_player : AudioStreamPlayer) -> void:
|
||||
_play_stream(stream_player)
|
||||
|
||||
func _tree_button_clicked_play_stream(_tree_item : TreeItem, _column : int, _id : int, _mouse_button_index : int, stream_player : AudioStreamPlayer) -> void:
|
||||
_play_stream(stream_player)
|
||||
|
||||
func _connect_stream_player(node : Node, stream_player : AudioStreamPlayer, signal_name : StringName, callable : Callable) -> void:
|
||||
if stream_player != null and not node.is_connected(signal_name, callable.bind(stream_player)):
|
||||
node.connect(signal_name, callable.bind(stream_player))
|
||||
|
||||
func connect_ui_sounds(node: Node) -> void:
|
||||
if node is Button:
|
||||
_connect_stream_player(node, button_hovered_player, &"mouse_entered", _play_stream)
|
||||
_connect_stream_player(node, button_focused_player, &"focus_entered", _play_stream)
|
||||
_connect_stream_player(node, button_pressed_player, &"pressed", _play_stream)
|
||||
elif node is TabBar:
|
||||
_connect_stream_player(node, tab_hovered_player, &"tab_hovered", _tab_event_play_stream)
|
||||
_connect_stream_player(node, tab_changed_player, &"tab_changed", _tab_event_play_stream)
|
||||
_connect_stream_player(node, tab_selected_player, &"tab_selected", _tab_event_play_stream)
|
||||
elif node is Slider:
|
||||
_connect_stream_player(node, slider_hovered_player, &"mouse_entered", _play_stream)
|
||||
_connect_stream_player(node, slider_focused_player, &"focus_entered", _play_stream)
|
||||
_connect_stream_player(node, slider_drag_started_player, &"drag_started", _play_stream)
|
||||
_connect_stream_player(node, slider_drag_ended_player, &"drag_ended", _slider_drag_ended_play_stream)
|
||||
elif node is LineEdit:
|
||||
_connect_stream_player(node, line_hovered_player, &"mouse_entered", _play_stream)
|
||||
_connect_stream_player(node, line_focused_player, &"focus_entered", _play_stream)
|
||||
_connect_stream_player(node, line_text_changed_player, &"text_changed", _line_event_play_stream)
|
||||
_connect_stream_player(node, line_text_submitted_player, &"text_submitted", _line_event_play_stream)
|
||||
_connect_stream_player(node, line_text_change_rejected_player, &"text_change_rejected", _line_event_play_stream)
|
||||
elif node is ItemList:
|
||||
_connect_stream_player(node, item_list_activated_player, &"item_activated", _item_list_play_stream)
|
||||
_connect_stream_player(node, item_list_selected_player, &"item_selected", _item_list_play_stream)
|
||||
elif node is Tree:
|
||||
_connect_stream_player(node, tree_item_activated_player, &"item_activated", _play_stream)
|
||||
_connect_stream_player(node, tree_item_selected_player, &"item_selected", _play_stream)
|
||||
_connect_stream_player(node, tree_button_clicked_player, &"button_clicked", _tree_button_clicked_play_stream)
|
||||
|
||||
func _recursive_connect_ui_sounds(current_node: Node, current_depth : int = 0) -> void:
|
||||
if current_depth >= MAX_DEPTH:
|
||||
return
|
||||
for node in current_node.get_children():
|
||||
connect_ui_sounds(node)
|
||||
_recursive_connect_ui_sounds(node, current_depth + 1)
|
||||
|
||||
func _ready() -> void:
|
||||
_build_all_stream_players()
|
||||
_recursive_connect_ui_sounds(root_node)
|
||||
persistent = persistent
|
||||
|
||||
func _exit_tree() -> void:
|
||||
var tree_node = get_tree()
|
||||
if tree_node.node_added.is_connected(connect_ui_sounds):
|
||||
tree_node.node_added.disconnect(connect_ui_sounds)
|
@ -0,0 +1 @@
|
||||
uid://b5oej1q4h7jvh
|
Reference in New Issue
Block a user