diff options
Diffstat (limited to 'game/addons/keychain/Keychain.gd')
-rw-r--r-- | game/addons/keychain/Keychain.gd | 174 |
1 files changed, 45 insertions, 129 deletions
diff --git a/game/addons/keychain/Keychain.gd b/game/addons/keychain/Keychain.gd index ff939f3..2288107 100644 --- a/game/addons/keychain/Keychain.gd +++ b/game/addons/keychain/Keychain.gd @@ -1,22 +1,29 @@ extends Node -const TRANSLATIONS_PATH := "res://addons/keychain/translations" const PROFILES_PATH := "user://shortcut_profiles" -# Change these settings -var profiles := [preload("profiles/default.tres")] -var selected_profile: ShortcutProfile = profiles[0] -var profile_index := 0 -# Syntax: "action_name": InputAction.new("Action Display Name", "Group", true) -# Note that "action_name" must already exist in the Project's Input Map. +## [Array] of [ShortcutProfile]s. +var profiles: Array[ShortcutProfile] = [preload("profiles/default.tres")] +var selected_profile := profiles[0] ## The currently selected [ShortcutProfile]. +var profile_index := 0 ## The index of the currently selected [ShortcutProfile]. +## [Dictionary] of [String] and [InputAction]. +## Syntax: "action_name": InputAction.new("Action Display Name", "Group", true) +## Note that "action_name" must already exist in the Project's Input Map. var actions := {} -# Syntax: "Group Name": InputGroup.new("Parent Group Name") +## [Dictionary] of [String] and [InputGroup]. +## Syntax: "Group Name": InputGroup.new("Parent Group Name") var groups := {} -var ignore_actions := [] +var ignore_actions: Array[StringName] = [] ## [Array] of [StringName] input map actions to ignore. +## If [code]true[/code], ignore Godot's default "ui_" input map actions. var ignore_ui_actions := true -var changeable_types := [true, true, true, true] -var multiple_menu_accelerators := false +## A [PackedByteArray] of [bool]s with a fixed length of 4. Used for developers to allow or +## forbid setting certain types of InputEvents. The first element is for [InputEventKey]s, +## the second for [InputEventMouseButton]s, the third for [InputEventJoypadButton]s +## and the fourth for [InputEventJoypadMotion]s. +var changeable_types: PackedByteArray = [true, true, true, true] +## The file path of the [code]config_file[/code]. var config_path := "user://cache.ini" +## Used to store the settings to the filesystem. var config_file: ConfigFile @@ -25,79 +32,11 @@ class InputAction: var group := "" var global := true - func _init(_display_name := "",_group := "",_global := true): + func _init(_display_name := "", _group := "", _global := true): display_name = _display_name group = _group global = _global - func update_node(_action: String) -> void: - pass - - func handle_input(_event: InputEvent, _action: String) -> bool: - return false - - -# This class is useful for the accelerators of PopupMenu items -# It's possible for PopupMenu items to have multiple shortcuts by using -# set_item_shortcut(), but we have no control over the accelerator text that appears. -# Thus, we are stuck with using accelerators instead of shortcuts. -# If Godot ever receives the ability to change the accelerator text of the items, -# we could in theory remove this class. -# If you don't care about PopupMenus in the same scene as ShortcutEdit -# such as projects like Pixelorama where everything is in the same scene, -# then you can ignore this class. -class MenuInputAction: - extends InputAction - var node_path := "" - var node: PopupMenu - var menu_item_id := 0 - var echo := false - - func _init( - _display_name := "", - _group := "", - _global := true, - _node_path := "", - _menu_item_id := 0, - _echo := false - ) -> void: - super._init(_display_name, _group, _global) - node_path = _node_path - menu_item_id = _menu_item_id - echo = _echo - - func get_node(root: Node) -> void: - var temp_node = root.get_node(node_path) - if temp_node is PopupMenu: - node = node - elif temp_node is MenuButton: - node = temp_node.get_popup() - - func update_node(action: String) -> void: - if !node: - return - var first_key: InputEventKey = Keychain.action_get_first_key(action) - var accel := first_key.get_keycode_with_modifiers() if first_key else 0 - node.set_item_accelerator(menu_item_id, accel) - - func handle_input(event: InputEvent, action: String) -> bool: - if not node: - return false - if event.is_action_pressed(action, false, true): - if event is InputEventKey: - var acc: int = node.get_item_accelerator(menu_item_id) - # If the event is the same as the menu item's accelerator, skip - if acc == event.get_keycode_with_modifiers(): - return true - node.emit_signal("id_pressed", menu_item_id) - return true - if event.is_action(action, true) and echo: - if event.is_echo(): - node.emit_signal("id_pressed", menu_item_id) - return true - - return false - class InputGroup: var parent_group := "" @@ -115,13 +54,10 @@ func _ready() -> void: if !config_path.is_empty(): config_file.load(config_path) - set_process_input(multiple_menu_accelerators) - # Load shortcut profiles DirAccess.make_dir_recursive_absolute(PROFILES_PATH) var profile_dir := DirAccess.open(PROFILES_PATH) - profile_dir.make_dir(PROFILES_PATH) - profile_dir.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 + profile_dir.list_dir_begin() var file_name = profile_dir.get_next() while file_name != "": if !profile_dir.current_is_dir(): @@ -143,35 +79,9 @@ func _ready() -> void: for profile in profiles: profile.fill_bindings() - var l18n_dir := DirAccess.open(TRANSLATIONS_PATH) - l18n_dir.list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547 - file_name = l18n_dir.get_next() - while file_name != "": - if !l18n_dir.current_is_dir(): - if file_name.get_extension() == "po": - var t: Translation = load(TRANSLATIONS_PATH.path_join(file_name)) - TranslationServer.add_translation(t) - file_name = l18n_dir.get_next() - profile_index = config_file.get_value("shortcuts", "shortcuts_profile", 0) change_profile(profile_index) - for action in actions: - var input_action: InputAction = actions[action] - if input_action is MenuInputAction: - input_action.get_node(get_tree().current_scene) - - -func _input(event: InputEvent) -> void: - if event is InputEventMouseMotion: - return - - for action in actions: - var input_action: InputAction = actions[action] - var done: bool = input_action.handle_input(event, action) - if done: - return - func change_profile(index: int) -> void: if index >= profiles.size(): @@ -184,29 +94,35 @@ func change_profile(index: int) -> void: action_add_event(action, event) -func action_add_event(action: String, event: InputEvent) -> void: +func action_add_event(action: StringName, event: InputEvent) -> void: InputMap.action_add_event(action, event) - if action in actions: - actions[action].update_node(action) -func action_erase_event(action: String, event: InputEvent) -> void: +func action_erase_event(action: StringName, event: InputEvent) -> void: InputMap.action_erase_event(action, event) - if action in actions: - actions[action].update_node(action) -func action_erase_events(action: String) -> void: +func action_erase_events(action: StringName) -> void: InputMap.action_erase_events(action) - if action in actions: - actions[action].update_node(action) - - -func action_get_first_key(action: String) -> InputEventKey: - var first_key: InputEventKey = null - var events := InputMap.action_get_events(action) - for event in events: - if event is InputEventKey: - first_key = event - break - return first_key + + +func load_translation(locale: String) -> void: + var translation = load("res://addons/keychain/translations".path_join(locale + ".po")) + if is_instance_valid(translation) and translation is Translation: + TranslationServer.add_translation(translation) + + +## Converts a [param text] with snake case to a more readable format, by replacing +## underscores with spaces. If [param capitalize_first_letter] is [code]true[/code], +## the first letter of the text is capitalized. +## E.g, "snake_case" would be converted to "Snake case" if +## [param capitalize_first_letter] is [code]true[/code], else it would be converted to +## "snake case". +func humanize_snake_case(text: String, capitalize_first_letter := true) -> String: + text = text.replace("_", " ") + if capitalize_first_letter: + var first_letter := text.left(1) + first_letter = first_letter.capitalize() + text = text.right(-1) + text = text.insert(0, first_letter) + return text |