diff --git a/game/addons/keychain/Keychain.gd b/game/addons/keychain/Keychain.gd index 99611894..1ba67c37 100644 --- a/game/addons/keychain/Keychain.gd +++ b/game/addons/keychain/Keychain.gd @@ -1,20 +1,20 @@ extends Node -const PROFILES_PATH := "user://shortcut_profiles" +signal profile_switched(profile: ShortcutProfile) +signal action_changed(action_name: String) -signal reload_keychain() +const PROFILES_PATH := "user://shortcut_profiles" +const DEFAULT_PROFILE := preload("profiles/default.tres") ## [Array] of [ShortcutProfile]s. -var profiles: Array[ShortcutProfile] = [preload("profiles/default.tres")] -var selected_profile := profiles[0] ## The currently selected [ShortcutProfile]. +var profiles: Array[ShortcutProfile] = [] +var selected_profile: ShortcutProfile ## 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 := {} -## [Dictionary] of [String] and [InputGroup]. +var actions: Dictionary[StringName, InputAction] = {} ## Syntax: "Group Name": InputGroup.new("Parent Group Name") -var groups := {} +var groups: Dictionary[StringName, InputGroup] = {} 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 @@ -37,12 +37,77 @@ class InputAction: var group := "" var global := true - func _init(_display_name := "", _group := "", _global := true): + func _init(_display_name := "", _group := "", _global := true) -> void: display_name = _display_name group = _group global = _global +class MouseMovementInputAction: + extends InputAction + + var action_name := &"" + ## The default direction of the mouse, towards where the value increments. + ## This should be set only once during an instance's initialization. + var default_mouse_dir := Vector2.RIGHT + ## The default sensitivity of the mouse for the value to change. + ## This should be set only once during an instance's initialization. + var default_sensitivity := 0.1 + + var mouse_dir := default_mouse_dir + var sensitivity := default_sensitivity: + set(value): + if is_zero_approx(value): + sensitivity = 0.001 + else: + sensitivity = value + + var motion_accum := 0.0 + + func _init( + _display_name := "", + _group := "", + _global := true, + _action_name := &"", + _default_mouse_dir := Vector2.RIGHT, + _default_sensitivity := 0.1 + ) -> void: + super(_display_name, _group, _global) + action_name = _action_name + default_mouse_dir = _default_mouse_dir + default_sensitivity = _default_sensitivity + + func get_action_distance(event: InputEvent, exact_match := false) -> float: + if event is InputEventMouseMotion and Input.is_action_pressed(action_name, exact_match): + var relative := (event as InputEventMouseMotion).relative + var delta := relative.dot(mouse_dir.normalized()) * sensitivity + return delta + return 0.0 + + func get_action_distance_int(event: InputEvent, exact_match := false) -> int: + if event is InputEventMouseMotion and Input.is_action_pressed(action_name, exact_match): + var relative := (event as InputEventMouseMotion).relative + var delta := relative.dot(mouse_dir.normalized()) * sensitivity + motion_accum += delta + + var step := int(motion_accum) + motion_accum -= step + + return step + return 0 + + func restore_to_default() -> void: + mouse_dir = default_mouse_dir + sensitivity = default_sensitivity + + func serialize() -> Dictionary: + return {"mouse_dir": mouse_dir, "sensitivity": sensitivity} + + func deserialize(dict: Dictionary) -> void: + mouse_dir = dict.get("mouse_dir", mouse_dir) + sensitivity = dict.get("sensitivity", sensitivity) + + class InputGroup: var parent_group := "" var folded := true @@ -57,6 +122,7 @@ func _init() -> void: for locale in TranslationServer.get_loaded_locales(): load_translation(locale) + func _ready() -> void: if !config_file: config_file = ConfigFile.new() @@ -73,38 +139,54 @@ func _ready() -> void: if file_name.get_extension() == "tres": var file := load(PROFILES_PATH.path_join(file_name)) if file is ShortcutProfile: + file.fill_bindings() profiles.append(file) file_name = profile_dir.get_next() # If there are no profiles besides the default, create one custom - if profiles.size() == 1: + if profiles.size() == 0: var profile := ShortcutProfile.new() profile.name = "Custom" profile.resource_path = PROFILES_PATH.path_join("custom.tres") var saved := profile.save() if saved: profiles.append(profile) - - initialize_profiles() - -func initialize_profiles() -> void: - for profile in profiles: - profile.fill_bindings() - profile_index = config_file.get_value("shortcuts", "shortcuts_profile", 0) change_profile(profile_index) - Keychain.reload_keychain.emit() + func change_profile(index: int) -> void: if index >= profiles.size(): index = profiles.size() - 1 profile_index = index selected_profile = profiles[index] - for action in selected_profile.bindings: - if not InputMap.has_action(action): continue - action_erase_events(action) - for event in selected_profile.bindings[action]: - action_add_event(action, event) + for action_name in selected_profile.bindings: + if not InputMap.has_action(action_name): + continue + action_erase_events(action_name) + for event in selected_profile.bindings[action_name]: + action_add_event(action_name, event) + if actions.has(action_name): + var input_action := actions[action_name] + if input_action is MouseMovementInputAction: + if selected_profile.mouse_movement_options.has(action_name): + var mm_options := selected_profile.mouse_movement_options[action_name] + input_action.deserialize(mm_options) + else: + input_action.restore_to_default() + profile_switched.emit(selected_profile) + + +func change_action(action_name: String) -> void: + selected_profile.change_action(action_name) + action_changed.emit(action_name) + + +func change_mouse_movement_action_settings(action: MouseMovementInputAction) -> void: + var action_name := action.action_name + selected_profile.mouse_movement_options[action_name] = action.serialize() + selected_profile.save() + action_changed.emit(action_name) func action_add_event(action: StringName, event: InputEvent) -> void: diff --git a/game/addons/keychain/Keychain.gd.uid b/game/addons/keychain/Keychain.gd.uid index bccae3f7..339fbdca 100644 --- a/game/addons/keychain/Keychain.gd.uid +++ b/game/addons/keychain/Keychain.gd.uid @@ -1 +1 @@ -uid://ba4bw6vqtoail +uid://dgiia2xg7fsud diff --git a/game/addons/keychain/ShortcutEdit.gd b/game/addons/keychain/ShortcutEdit.gd index 40a4ee49..382bba59 100644 --- a/game/addons/keychain/ShortcutEdit.gd +++ b/game/addons/keychain/ShortcutEdit.gd @@ -64,7 +64,11 @@ const JOY_AXIS_NAMES: PackedStringArray = [ ] var currently_editing_tree_item: TreeItem +var currently_editing_mouse_movement_action: Keychain.MouseMovementInputAction var is_editing := false +var current_name_filter := "" +var current_event_filter: InputEvent +var filter_by_shortcut_line_edit_has_focus := false # Textures taken from Godot https://github.com/godotengine/godot/tree/master/editor/icons var add_tex: Texture2D = preload("assets/add.svg") var edit_tex: Texture2D = preload("assets/edit.svg") @@ -77,10 +81,25 @@ var mouse_tex: Texture2D = preload("assets/mouse.svg") var shortcut_tex: Texture2D = preload("assets/shortcut.svg") var folder_tex: Texture2D = preload("assets/folder.svg") +@onready var filter_by_name_line_edit: LineEdit = %FilterByNameLineEdit +@onready var filter_by_shortcut_line_edit: LineEdit = %FilterByShortcutLineEdit @onready var tree: Tree = $VBoxContainer/ShortcutTree @onready var profile_option_button: OptionButton = find_child("ProfileOptionButton") @onready var rename_profile_button: Button = find_child("RenameProfile") @onready var delete_profile_button: Button = find_child("DeleteProfile") + +@onready var mouse_movement_options: HBoxContainer = $VBoxContainer/MouseMovementOptions +@onready var mm_top_left: Button = %MMTopLeft +@onready var mm_top: Button = %MMTop +@onready var mm_top_right: Button = %MMTopRight +@onready var mm_left: Button = %MMLeft +@onready var mm_center: Button = %MMCenter +@onready var mm_right: Button = %MMRight +@onready var mm_bottom_left: Button = %MMBottomLeft +@onready var mm_bottom: Button = %MMBottom +@onready var mm_bottom_right: Button = %MMBottomRight +@onready var sensitivity_range: SpinBox = $VBoxContainer/MouseMovementOptions/SensitivityRange + @onready var shortcut_type_menu: PopupMenu = $ShortcutTypeMenu @onready var keyboard_shortcut_selector: ConfirmationDialog = $KeyboardShortcutSelectorDialog @onready var mouse_shortcut_selector: ConfirmationDialog = $MouseShortcutSelectorDialog @@ -89,6 +108,7 @@ var folder_tex: Texture2D = preload("assets/folder.svg") @onready var profile_settings: ConfirmationDialog = $ProfileSettings @onready var profile_name: LineEdit = $ProfileSettings/ProfileName @onready var delete_confirmation: ConfirmationDialog = $DeleteConfirmation +@onready var reset_confirmation: ConfirmationDialog = $ResetConfirmation func _ready() -> void: @@ -107,16 +127,12 @@ func _ready() -> void: profile_option_button.select(Keychain.profile_index) _on_ProfileOptionButton_item_selected(Keychain.profile_index) + mm_top_left.button_group.pressed.connect(_on_mouse_movement_angle_changed) if OS.get_name() == "Web": $VBoxContainer/HBoxContainer/OpenProfileFolder.queue_free() - Keychain.reload_keychain.connect(_on_reload_keychain) - -func _on_reload_keychain() -> void: - _on_ProfileOptionButton_item_selected(Keychain.profile_index) func _construct_tree() -> void: - var buttons_disabled := false if Keychain.selected_profile.customizable else true var tree_root: TreeItem = tree.create_item() for group in Keychain.groups: # Create groups var input_group: Keychain.InputGroup = Keychain.groups[group] @@ -149,9 +165,11 @@ func _construct_tree() -> void: for event in InputMap.action_get_events(action): add_event_tree_item(event, tree_item) + var buttons_disabled := false if Keychain.selected_profile.customizable else true tree_item.add_button(0, add_tex, 0, buttons_disabled, "Add") tree_item.add_button(0, delete_tex, 1, buttons_disabled, "Delete") tree_item.collapsed = true + mouse_movement_options.hide() func _fill_selector_options() -> void: @@ -265,6 +283,90 @@ func event_to_str(event: InputEvent) -> String: return output +func _on_filter_by_name_line_edit_text_changed(new_text: String) -> void: + current_name_filter = new_text.strip_edges() + apply_search_filters() + + +func _on_filter_by_shortcut_line_edit_gui_input(event: InputEvent) -> void: + if ( + not event is InputEventKey + and not event is InputEventMouseButton + and not event is InputEventJoypadButton + ): + return + if event.pressed: + if event is InputEventMouseButton: + if not filter_by_shortcut_line_edit_has_focus: + return + if event.position.x >= filter_by_shortcut_line_edit.get_rect().size.x - 30: + return + current_event_filter = event + filter_by_shortcut_line_edit.set_deferred(&"text", event.as_text()) + apply_search_filters() + + +func _on_filter_by_shortcut_line_edit_text_changed(new_text: String) -> void: + if not new_text.is_empty(): + return + current_event_filter = null + apply_search_filters() + + +func _on_clear_all_filters_pressed() -> void: + filter_by_name_line_edit.text = "" + filter_by_shortcut_line_edit.text = "" + current_name_filter = "" + current_event_filter = null + apply_search_filters() + + +func apply_search_filters() -> void: + var tree_item: TreeItem = tree.get_root().get_first_child() + var results: Array[TreeItem] = [] + var should_reset := ( + not is_instance_valid(current_event_filter) and current_name_filter.is_empty() + ) + while tree_item != null: # Loop through Tree's TreeItems. + if is_instance_valid(current_event_filter): + var metadata = tree_item.get_metadata(0) + if metadata is InputEvent: + if current_event_filter.is_match(metadata): + if current_name_filter.is_empty(): + results.append(tree_item) + else: + var parent := tree_item.get_parent() + if current_name_filter.is_subsequence_ofn(parent.get_text(0)): + results.append(tree_item) + elif not current_name_filter.is_empty(): + var metadata = tree_item.get_metadata(0) + if metadata is StringName: + if current_name_filter.is_subsequence_ofn(tree_item.get_text(0)): + results.append(tree_item) + elif metadata is InputEvent: + tree_item = tree_item.get_next_in_tree() + continue + + if should_reset: + tree_item.visible = true + else: + tree_item.collapsed = true + tree_item.visible = false + tree_item = tree_item.get_next_in_tree() + var expanded: Array[TreeItem] = [] + for result in results: + var item: TreeItem = result + while item.get_parent(): + if expanded.has(item): + break + item.collapsed = false + item.visible = true + expanded.append(item) + item = item.get_parent() + if not results.is_empty(): + tree.scroll_to_item(results[0]) + + func _on_shortcut_tree_button_clicked(item: TreeItem, _column: int, id: int, _mbi: int) -> void: var action = item.get_metadata(0) currently_editing_tree_item = item @@ -278,7 +380,7 @@ func _on_shortcut_tree_button_clicked(item: TreeItem, _column: int, id: int, _mb shortcut_type_menu.popup_on_parent(rect) elif id == 1: # Delete Keychain.action_erase_events(action) - Keychain.selected_profile.change_action(action) + Keychain.change_action(action) for child in item.get_children(): child.free() @@ -286,48 +388,114 @@ func _on_shortcut_tree_button_clicked(item: TreeItem, _column: int, id: int, _mb var parent_action = item.get_parent().get_metadata(0) if id == 0: # Edit if action is InputEventKey: - keyboard_shortcut_selector.popup_centered() + keyboard_shortcut_selector.popup_centered_clamped() elif action is InputEventMouseButton: - mouse_shortcut_selector.popup_centered() + mouse_shortcut_selector.popup_centered_clamped() elif action is InputEventJoypadButton: - joy_key_shortcut_selector.popup_centered() + joy_key_shortcut_selector.popup_centered_clamped() elif action is InputEventJoypadMotion: - joy_axis_shortcut_selector.popup_centered() + joy_axis_shortcut_selector.popup_centered_clamped() elif id == 1: # Delete if not parent_action is StringName: return Keychain.action_erase_event(parent_action, action) - Keychain.selected_profile.change_action(parent_action) + Keychain.change_action(parent_action) item.free() +func _on_shortcut_tree_item_selected() -> void: + var selected_item: TreeItem = tree.get_selected() + var action = selected_item.get_metadata(0) + if action is StringName: + if not Keychain.actions.has(action): + mouse_movement_options.visible = false + return + var keychain_action := Keychain.actions[action] + if keychain_action is Keychain.MouseMovementInputAction: + mouse_movement_options.visible = true + currently_editing_mouse_movement_action = keychain_action + _press_mouse_movement_angle_button() + sensitivity_range.set_value_no_signal( + currently_editing_mouse_movement_action.sensitivity + ) + else: + mouse_movement_options.visible = false + + func _on_ShortcutTree_item_activated() -> void: var selected_item: TreeItem = tree.get_selected() if selected_item.get_button_count(0) > 0 and !selected_item.is_button_disabled(0, 0): _on_shortcut_tree_button_clicked(tree.get_selected(), 0, 0, 0) + elif selected_item.get_button_count(0) == 0: # Group item + selected_item.collapsed = not selected_item.collapsed func _on_ShortcutTypeMenu_id_pressed(id: int) -> void: if id == KEYBOARD: - keyboard_shortcut_selector.popup_centered() + keyboard_shortcut_selector.popup_centered_clamped() elif id == MOUSE: - mouse_shortcut_selector.popup_centered() + mouse_shortcut_selector.popup_centered_clamped() elif id == JOY_BUTTON: - joy_key_shortcut_selector.popup_centered() + joy_key_shortcut_selector.popup_centered_clamped() elif id == JOY_AXIS: - joy_axis_shortcut_selector.popup_centered() + joy_axis_shortcut_selector.popup_centered_clamped() + + +func _on_mouse_movement_angle_changed(button: BaseButton) -> void: + match button: + mm_top_left: + currently_editing_mouse_movement_action.mouse_dir = Vector2(-1, -1) + mm_top: + currently_editing_mouse_movement_action.mouse_dir = Vector2.UP + mm_top_right: + currently_editing_mouse_movement_action.mouse_dir = Vector2(1, -1) + mm_left: + currently_editing_mouse_movement_action.mouse_dir = Vector2.LEFT + mm_right: + currently_editing_mouse_movement_action.mouse_dir = Vector2.RIGHT + mm_bottom_left: + currently_editing_mouse_movement_action.mouse_dir = Vector2(-1, 1) + mm_bottom: + currently_editing_mouse_movement_action.mouse_dir = Vector2.DOWN + mm_bottom_right: + currently_editing_mouse_movement_action.mouse_dir = Vector2(1, 1) + Keychain.change_mouse_movement_action_settings(currently_editing_mouse_movement_action) + + +func _press_mouse_movement_angle_button() -> void: + var dir := currently_editing_mouse_movement_action.mouse_dir + match dir: + Vector2(-1, -1): + mm_top_left.button_pressed = true + Vector2.UP: + mm_top.button_pressed = true + Vector2(1, -1): + mm_top_right.button_pressed = true + Vector2.LEFT: + mm_left.button_pressed = true + Vector2.RIGHT: + mm_right.button_pressed = true + Vector2(-1, 1): + mm_bottom_left.button_pressed = true + Vector2.DOWN: + mm_bottom.button_pressed = true + Vector2(1, 1): + mm_bottom_right.button_pressed = true + + +func _on_sensitivity_range_value_changed(value: float) -> void: + currently_editing_mouse_movement_action.sensitivity = value + Keychain.change_mouse_movement_action_settings(currently_editing_mouse_movement_action) func _on_ProfileOptionButton_item_selected(index: int) -> void: Keychain.change_profile(index) rename_profile_button.disabled = false if Keychain.selected_profile.customizable else true delete_profile_button.disabled = false if Keychain.selected_profile.customizable else true + if Keychain.profiles.size() == 1: + delete_profile_button.disabled = true - # Re-construct the tree - for group in Keychain.groups: - Keychain.groups[group].tree_item = null - tree.clear() - _construct_tree() + _reconstruct_tree() Keychain.config_file.set_value("shortcuts", "shortcuts_profile", index) Keychain.config_file.save(Keychain.config_path) @@ -336,18 +504,22 @@ func _on_NewProfile_pressed() -> void: is_editing = false profile_name.text = "New Shortcut Profile" profile_settings.title = "New Shortcut Profile" - profile_settings.popup_centered() + profile_settings.popup_centered_clamped() + + +func _on_reset_profile_pressed() -> void: + reset_confirmation.popup_centered_clamped() func _on_RenameProfile_pressed() -> void: is_editing = true profile_name.text = Keychain.selected_profile.name profile_settings.title = "Rename Shortcut Profile" - profile_settings.popup_centered() + profile_settings.popup_centered_clamped() func _on_DeleteProfile_pressed() -> void: - delete_confirmation.popup_centered() + delete_confirmation.popup_centered_clamped() func _on_OpenProfileFolder_pressed() -> void: @@ -359,7 +531,6 @@ func _on_ProfileSettings_confirmed() -> void: var profile := ShortcutProfile.new() profile.name = profile_name.text profile.resource_path = Keychain.PROFILES_PATH.path_join(file_name) - profile.fill_bindings() var saved := profile.save() if not saved: return @@ -380,7 +551,7 @@ func _on_ProfileSettings_confirmed() -> void: func _delete_profile_file(file_name: String) -> void: var dir := DirAccess.open(file_name.get_base_dir()) - var err := dir.get_open_error() + var err := DirAccess.get_open_error() if err != OK: print("Error deleting shortcut profile %s. Error code: %s" % [file_name, err]) return @@ -396,3 +567,24 @@ func _on_DeleteConfirmation_confirmed() -> void: Keychain.profile_index = 0 profile_option_button.select(Keychain.profile_index) _on_ProfileOptionButton_item_selected(Keychain.profile_index) + + +func _on_reset_confirmation_confirmed() -> void: + Keychain.selected_profile.copy_bindings_from(Keychain.DEFAULT_PROFILE) + Keychain.change_profile(Keychain.profile_index) + _reconstruct_tree() + + +func _reconstruct_tree() -> void: + for group in Keychain.groups: + Keychain.groups[group].tree_item = null + tree.clear() + _construct_tree() + + +func _on_filter_by_shortcut_line_edit_focus_entered() -> void: + set_deferred(&"filter_by_shortcut_line_edit_has_focus", true) + + +func _on_filter_by_shortcut_line_edit_focus_exited() -> void: + filter_by_shortcut_line_edit_has_focus = false diff --git a/game/addons/keychain/ShortcutEdit.gd.uid b/game/addons/keychain/ShortcutEdit.gd.uid index f947ecc6..958a2d34 100644 --- a/game/addons/keychain/ShortcutEdit.gd.uid +++ b/game/addons/keychain/ShortcutEdit.gd.uid @@ -1 +1 @@ -uid://d3kk6vtioc1aq +uid://dpciapd2x2va6 diff --git a/game/addons/keychain/ShortcutEdit.tscn b/game/addons/keychain/ShortcutEdit.tscn index 5f88c330..bad49fd3 100644 --- a/game/addons/keychain/ShortcutEdit.tscn +++ b/game/addons/keychain/ShortcutEdit.tscn @@ -1,11 +1,23 @@ -[gd_scene load_steps=7 format=3 uid="uid://bq7ibhm0txl5p"] +[gd_scene load_steps=18 format=3 uid="uid://bq7ibhm0txl5p"] -[ext_resource type="Script" uid="uid://d3kk6vtioc1aq" path="res://addons/keychain/ShortcutEdit.gd" id="1"] +[ext_resource type="Script" uid="uid://dpciapd2x2va6" path="res://addons/keychain/ShortcutEdit.gd" id="1"] [ext_resource type="Texture2D" uid="uid://ca58ufal2ufd8" path="res://addons/keychain/assets/joy_button.svg" id="2"] +[ext_resource type="Texture2D" uid="uid://0ij8aasy3k3b" path="res://addons/keychain/assets/search.svg" id="2_4odqy"] +[ext_resource type="Texture2D" uid="uid://cgsvoct3wwbjb" path="res://addons/keychain/assets/arrows/down.png" id="2_b4f3q"] +[ext_resource type="Texture2D" uid="uid://esi4oenejswj" path="res://addons/keychain/assets/arrows/top_left.png" id="2_gs4p1"] +[ext_resource type="Texture2D" uid="uid://cmh8eaibhn5y8" path="res://addons/keychain/assets/keyboard_physical.svg" id="2_wps2m"] [ext_resource type="Texture2D" uid="uid://c2s5rm4nec5yh" path="res://addons/keychain/assets/keyboard.svg" id="3"] +[ext_resource type="Texture2D" uid="uid://b337qel4762m4" path="res://addons/keychain/assets/arrows/up.png" id="3_gw1s5"] [ext_resource type="Texture2D" uid="uid://bb6q6om3d08cm" path="res://addons/keychain/assets/joy_axis.svg" id="4"] +[ext_resource type="Texture2D" uid="uid://yhwkkevw7lur" path="res://addons/keychain/assets/arrows/left.png" id="4_dmnk0"] +[ext_resource type="Texture2D" uid="uid://cr4lfb2lrtl7a" path="res://addons/keychain/assets/arrows/top_right.png" id="4_wps2m"] [ext_resource type="Texture2D" uid="uid://bma7xj2rqqcr8" path="res://addons/keychain/assets/mouse.svg" id="5"] +[ext_resource type="Texture2D" uid="uid://bj5ctot6clu13" path="res://addons/keychain/assets/arrows/right.png" id="5_nwpwn"] [ext_resource type="PackedScene" uid="uid://bfjcafe2kvx7n" path="res://addons/keychain/ShortcutSelectorDialog.tscn" id="6"] +[ext_resource type="Texture2D" uid="uid://b3io8jf2b3w1y" path="res://addons/keychain/assets/arrows/bottom_left.png" id="7_4odqy"] +[ext_resource type="Texture2D" uid="uid://b7gkuibgeavkl" path="res://addons/keychain/assets/arrows/bottom_right.png" id="9_v7k3h"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_b4f3q"] [node name="ShortcutEdit" type="Control"] layout_mode = 3 @@ -44,6 +56,12 @@ size_flags_horizontal = 3 mouse_default_cursor_shape = 2 text = "New" +[node name="ResetProfile" type="Button" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +mouse_default_cursor_shape = 2 +text = "Reset" + [node name="RenameProfile" type="Button" parent="VBoxContainer/HBoxContainer"] layout_mode = 2 size_flags_horizontal = 3 @@ -62,11 +80,135 @@ size_flags_horizontal = 3 mouse_default_cursor_shape = 2 text = "Open Folder" +[node name="Filters" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="FilterByNameLineEdit" type="LineEdit" parent="VBoxContainer/Filters"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Filter by name" +clear_button_enabled = true +right_icon = ExtResource("2_4odqy") + +[node name="FilterByShortcutLineEdit" type="LineEdit" parent="VBoxContainer/Filters"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +placeholder_text = "Filter by shortcut" +context_menu_enabled = false +clear_button_enabled = true +shortcut_keys_enabled = false +middle_mouse_paste_enabled = false +selecting_enabled = false +right_icon = ExtResource("2_wps2m") + +[node name="ClearAllFilters" type="Button" parent="VBoxContainer/Filters"] +layout_mode = 2 +text = "Clear all" + [node name="ShortcutTree" type="Tree" parent="VBoxContainer"] layout_mode = 2 size_flags_vertical = 3 hide_root = true +[node name="MouseMovementOptions" type="HBoxContainer" parent="VBoxContainer"] +visible = false +layout_mode = 2 + +[node name="AngleLabel" type="Label" parent="VBoxContainer/MouseMovementOptions"] +layout_mode = 2 +text = "Angle:" + +[node name="AngleOptions" type="GridContainer" parent="VBoxContainer/MouseMovementOptions"] +layout_mode = 2 +columns = 3 + +[node name="MMTopLeft" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_b4f3q") +icon = ExtResource("2_gs4p1") +icon_alignment = 1 + +[node name="MMTop" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_b4f3q") +icon = ExtResource("3_gw1s5") +icon_alignment = 1 + +[node name="MMTopRight" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_b4f3q") +icon = ExtResource("4_wps2m") +icon_alignment = 1 + +[node name="MMLeft" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_b4f3q") +icon = ExtResource("4_dmnk0") +icon_alignment = 1 + +[node name="MMCenter" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +disabled = true +toggle_mode = true +button_group = SubResource("ButtonGroup_b4f3q") +icon_alignment = 1 + +[node name="MMRight" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +toggle_mode = true +button_pressed = true +button_group = SubResource("ButtonGroup_b4f3q") +icon = ExtResource("5_nwpwn") +icon_alignment = 1 + +[node name="MMBottomLeft" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_b4f3q") +icon = ExtResource("7_4odqy") +icon_alignment = 1 + +[node name="MMBottom" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_b4f3q") +icon = ExtResource("2_b4f3q") +icon_alignment = 1 + +[node name="MMBottomRight" type="Button" parent="VBoxContainer/MouseMovementOptions/AngleOptions"] +unique_name_in_owner = true +layout_mode = 2 +toggle_mode = true +button_group = SubResource("ButtonGroup_b4f3q") +icon = ExtResource("9_v7k3h") +icon_alignment = 1 + +[node name="SensitivityLabel" type="Label" parent="VBoxContainer/MouseMovementOptions"] +layout_mode = 2 +text = "Sensitivity:" + +[node name="SensitivityRange" type="SpinBox" parent="VBoxContainer/MouseMovementOptions"] +layout_mode = 2 +min_value = 0.001 +step = 0.001 +value = 0.1 +allow_greater = true +custom_arrow_step = 0.1 + [node name="ShortcutTypeMenu" type="PopupMenu" parent="."] size = Vector2i(154, 116) item_count = 4 @@ -110,13 +252,27 @@ offset_bottom = 51.0 size = Vector2i(427, 100) dialog_text = "Are you sure you want to delete this shortcut profile?" +[node name="ResetConfirmation" type="ConfirmationDialog" parent="."] +size = Vector2i(427, 100) +dialog_text = "Are you sure you want to restore all shortcuts to their default settings?" + [connection signal="item_selected" from="VBoxContainer/HBoxContainer/ProfileOptionButton" to="." method="_on_ProfileOptionButton_item_selected"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/NewProfile" to="." method="_on_NewProfile_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/ResetProfile" to="." method="_on_reset_profile_pressed"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/RenameProfile" to="." method="_on_RenameProfile_pressed"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/DeleteProfile" to="." method="_on_DeleteProfile_pressed"] [connection signal="pressed" from="VBoxContainer/HBoxContainer/OpenProfileFolder" to="." method="_on_OpenProfileFolder_pressed"] +[connection signal="text_changed" from="VBoxContainer/Filters/FilterByNameLineEdit" to="." method="_on_filter_by_name_line_edit_text_changed"] +[connection signal="focus_entered" from="VBoxContainer/Filters/FilterByShortcutLineEdit" to="." method="_on_filter_by_shortcut_line_edit_focus_entered"] +[connection signal="focus_exited" from="VBoxContainer/Filters/FilterByShortcutLineEdit" to="." method="_on_filter_by_shortcut_line_edit_focus_exited"] +[connection signal="gui_input" from="VBoxContainer/Filters/FilterByShortcutLineEdit" to="." method="_on_filter_by_shortcut_line_edit_gui_input"] +[connection signal="text_changed" from="VBoxContainer/Filters/FilterByShortcutLineEdit" to="." method="_on_filter_by_shortcut_line_edit_text_changed"] +[connection signal="pressed" from="VBoxContainer/Filters/ClearAllFilters" to="." method="_on_clear_all_filters_pressed"] [connection signal="button_clicked" from="VBoxContainer/ShortcutTree" to="." method="_on_shortcut_tree_button_clicked"] [connection signal="item_activated" from="VBoxContainer/ShortcutTree" to="." method="_on_ShortcutTree_item_activated"] +[connection signal="item_selected" from="VBoxContainer/ShortcutTree" to="." method="_on_shortcut_tree_item_selected"] +[connection signal="value_changed" from="VBoxContainer/MouseMovementOptions/SensitivityRange" to="." method="_on_sensitivity_range_value_changed"] [connection signal="id_pressed" from="ShortcutTypeMenu" to="." method="_on_ShortcutTypeMenu_id_pressed"] [connection signal="confirmed" from="ProfileSettings" to="." method="_on_ProfileSettings_confirmed"] [connection signal="confirmed" from="DeleteConfirmation" to="." method="_on_DeleteConfirmation_confirmed"] +[connection signal="confirmed" from="ResetConfirmation" to="." method="_on_reset_confirmation_confirmed"] diff --git a/game/addons/keychain/ShortcutProfile.gd b/game/addons/keychain/ShortcutProfile.gd index e7935a3b..188bf14f 100644 --- a/game/addons/keychain/ShortcutProfile.gd +++ b/game/addons/keychain/ShortcutProfile.gd @@ -3,14 +3,16 @@ extends Resource @export var name := "" @export var customizable := true -@export var bindings := {} +@export var bindings: Dictionary[StringName, Array] = {} +@export var mouse_movement_options: Dictionary[StringName, Dictionary] = {} func _init() -> void: bindings = bindings.duplicate(true) + fill_bindings(false) -func fill_bindings() -> void: +func fill_bindings(should_save := true) -> void: var unnecessary_actions = bindings.duplicate() # Checks if the profile has any unused actions for action in InputMap.get_actions(): if not action in bindings: @@ -21,13 +23,20 @@ func fill_bindings() -> void: unnecessary_actions.erase(action) continue bindings.erase(action) + if should_save: + save() + + +func copy_bindings_from(other_profile: ShortcutProfile) -> void: + bindings = other_profile.bindings.duplicate(true) + mouse_movement_options = other_profile.mouse_movement_options.duplicate(true) save() -func change_action(action: String) -> void: +func change_action(action_name: String) -> void: if not customizable: return - bindings[action] = InputMap.action_get_events(action) + bindings[action_name] = InputMap.action_get_events(action_name) save() diff --git a/game/addons/keychain/ShortcutProfile.gd.uid b/game/addons/keychain/ShortcutProfile.gd.uid index 02b25e64..fa39f08e 100644 --- a/game/addons/keychain/ShortcutProfile.gd.uid +++ b/game/addons/keychain/ShortcutProfile.gd.uid @@ -1 +1 @@ -uid://bqeixyoeq23tm +uid://bmtkqh6xvat7 diff --git a/game/addons/keychain/ShortcutSelectorDialog.gd b/game/addons/keychain/ShortcutSelectorDialog.gd index fb28434b..ec4c04b6 100644 --- a/game/addons/keychain/ShortcutSelectorDialog.gd +++ b/game/addons/keychain/ShortcutSelectorDialog.gd @@ -101,9 +101,8 @@ func _set_shortcut(action: StringName, old_event: InputEvent, new_event: InputEv var action_to_replace: StringName = matching_pair[0] var input_to_replace: InputEvent = matching_pair[1] Keychain.action_erase_event(action_to_replace, input_to_replace) - Keychain.selected_profile.change_action(action_to_replace) + Keychain.change_action(action_to_replace) var tree_item: TreeItem = root.tree.get_root() - var prev_tree_item: TreeItem while tree_item != null: # Loop through Tree's TreeItems... var metadata = tree_item.get_metadata(0) if metadata is InputEvent: @@ -116,7 +115,7 @@ func _set_shortcut(action: StringName, old_event: InputEvent, new_event: InputEv tree_item = tree_item.get_next_in_tree() Keychain.action_add_event(action, new_event) - Keychain.selected_profile.change_action(action) + Keychain.change_action(action) return true diff --git a/game/addons/keychain/ShortcutSelectorDialog.gd.uid b/game/addons/keychain/ShortcutSelectorDialog.gd.uid index 176a2846..da09c096 100644 --- a/game/addons/keychain/ShortcutSelectorDialog.gd.uid +++ b/game/addons/keychain/ShortcutSelectorDialog.gd.uid @@ -1 +1 @@ -uid://dstt62ti7x6xn +uid://ji2g5biygmmd diff --git a/game/addons/keychain/ShortcutSelectorDialog.tscn b/game/addons/keychain/ShortcutSelectorDialog.tscn index 73408bde..0cc18ec3 100644 --- a/game/addons/keychain/ShortcutSelectorDialog.tscn +++ b/game/addons/keychain/ShortcutSelectorDialog.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=2 format=3 uid="uid://bfjcafe2kvx7n"] -[ext_resource type="Script" uid="uid://dstt62ti7x6xn" path="res://addons/keychain/ShortcutSelectorDialog.gd" id="1"] +[ext_resource type="Script" uid="uid://ji2g5biygmmd" path="res://addons/keychain/ShortcutSelectorDialog.gd" id="1"] [node name="ShortcutSelectorDialog" type="ConfirmationDialog"] size = Vector2i(417, 169) diff --git a/game/addons/keychain/assets/arrows/bottom_left.png b/game/addons/keychain/assets/arrows/bottom_left.png new file mode 100644 index 00000000..e56c9208 Binary files /dev/null and b/game/addons/keychain/assets/arrows/bottom_left.png differ diff --git a/game/addons/keychain/assets/arrows/bottom_left.png.import b/game/addons/keychain/assets/arrows/bottom_left.png.import new file mode 100644 index 00000000..e7e6c7ec --- /dev/null +++ b/game/addons/keychain/assets/arrows/bottom_left.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b3io8jf2b3w1y" +path="res://.godot/imported/bottom_left.png-70322cf92ed47ef9fb9e9bc20955dfd9.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/arrows/bottom_left.png" +dest_files=["res://.godot/imported/bottom_left.png-70322cf92ed47ef9fb9e9bc20955dfd9.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/addons/keychain/assets/arrows/bottom_right.png b/game/addons/keychain/assets/arrows/bottom_right.png new file mode 100644 index 00000000..bff81258 Binary files /dev/null and b/game/addons/keychain/assets/arrows/bottom_right.png differ diff --git a/game/addons/keychain/assets/arrows/bottom_right.png.import b/game/addons/keychain/assets/arrows/bottom_right.png.import new file mode 100644 index 00000000..01ed2397 --- /dev/null +++ b/game/addons/keychain/assets/arrows/bottom_right.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b7gkuibgeavkl" +path="res://.godot/imported/bottom_right.png-9d2b3283853c122c6405a136e996abe0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/arrows/bottom_right.png" +dest_files=["res://.godot/imported/bottom_right.png-9d2b3283853c122c6405a136e996abe0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/addons/keychain/assets/arrows/down.png b/game/addons/keychain/assets/arrows/down.png new file mode 100644 index 00000000..d039fef4 Binary files /dev/null and b/game/addons/keychain/assets/arrows/down.png differ diff --git a/game/addons/keychain/assets/arrows/down.png.import b/game/addons/keychain/assets/arrows/down.png.import new file mode 100644 index 00000000..0f317bee --- /dev/null +++ b/game/addons/keychain/assets/arrows/down.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cgsvoct3wwbjb" +path="res://.godot/imported/down.png-8649aa2bcc09abeceb6a1be3098abe52.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/arrows/down.png" +dest_files=["res://.godot/imported/down.png-8649aa2bcc09abeceb6a1be3098abe52.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/addons/keychain/assets/arrows/left.png b/game/addons/keychain/assets/arrows/left.png new file mode 100644 index 00000000..d3753f54 Binary files /dev/null and b/game/addons/keychain/assets/arrows/left.png differ diff --git a/game/addons/keychain/assets/arrows/left.png.import b/game/addons/keychain/assets/arrows/left.png.import new file mode 100644 index 00000000..938769d5 --- /dev/null +++ b/game/addons/keychain/assets/arrows/left.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://yhwkkevw7lur" +path="res://.godot/imported/left.png-28bcee1e175f55e11f3dd755b22f301a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/arrows/left.png" +dest_files=["res://.godot/imported/left.png-28bcee1e175f55e11f3dd755b22f301a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/addons/keychain/assets/arrows/right.png b/game/addons/keychain/assets/arrows/right.png new file mode 100644 index 00000000..681c67dc Binary files /dev/null and b/game/addons/keychain/assets/arrows/right.png differ diff --git a/game/addons/keychain/assets/arrows/right.png.import b/game/addons/keychain/assets/arrows/right.png.import new file mode 100644 index 00000000..c67fdac2 --- /dev/null +++ b/game/addons/keychain/assets/arrows/right.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bj5ctot6clu13" +path="res://.godot/imported/right.png-9afb447ac90f3038b6c5c972fb70dd1b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/arrows/right.png" +dest_files=["res://.godot/imported/right.png-9afb447ac90f3038b6c5c972fb70dd1b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/addons/keychain/assets/arrows/top_left.png b/game/addons/keychain/assets/arrows/top_left.png new file mode 100644 index 00000000..cfdc8e9a Binary files /dev/null and b/game/addons/keychain/assets/arrows/top_left.png differ diff --git a/game/addons/keychain/assets/arrows/top_left.png.import b/game/addons/keychain/assets/arrows/top_left.png.import new file mode 100644 index 00000000..3e637ea3 --- /dev/null +++ b/game/addons/keychain/assets/arrows/top_left.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://esi4oenejswj" +path="res://.godot/imported/top_left.png-dcc3d109cf7558350f725395ee8a16c5.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/arrows/top_left.png" +dest_files=["res://.godot/imported/top_left.png-dcc3d109cf7558350f725395ee8a16c5.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/addons/keychain/assets/arrows/top_right.png b/game/addons/keychain/assets/arrows/top_right.png new file mode 100644 index 00000000..9515c48c Binary files /dev/null and b/game/addons/keychain/assets/arrows/top_right.png differ diff --git a/game/addons/keychain/assets/arrows/top_right.png.import b/game/addons/keychain/assets/arrows/top_right.png.import new file mode 100644 index 00000000..26dd242c --- /dev/null +++ b/game/addons/keychain/assets/arrows/top_right.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cr4lfb2lrtl7a" +path="res://.godot/imported/top_right.png-e666f3cd901985122bff1c790593444e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/arrows/top_right.png" +dest_files=["res://.godot/imported/top_right.png-e666f3cd901985122bff1c790593444e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/addons/keychain/assets/arrows/up.png b/game/addons/keychain/assets/arrows/up.png new file mode 100644 index 00000000..b5f8f570 Binary files /dev/null and b/game/addons/keychain/assets/arrows/up.png differ diff --git a/game/addons/keychain/assets/arrows/up.png.import b/game/addons/keychain/assets/arrows/up.png.import new file mode 100644 index 00000000..b99815d0 --- /dev/null +++ b/game/addons/keychain/assets/arrows/up.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b337qel4762m4" +path="res://.godot/imported/up.png-02f7906dca0886b3b744d8d6606dd52e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/arrows/up.png" +dest_files=["res://.godot/imported/up.png-02f7906dca0886b3b744d8d6606dd52e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/game/addons/keychain/assets/search.svg b/game/addons/keychain/assets/search.svg new file mode 100644 index 00000000..736d5535 --- /dev/null +++ b/game/addons/keychain/assets/search.svg @@ -0,0 +1 @@ + diff --git a/game/addons/keychain/assets/search.svg.import b/game/addons/keychain/assets/search.svg.import new file mode 100644 index 00000000..2c982ce0 --- /dev/null +++ b/game/addons/keychain/assets/search.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://0ij8aasy3k3b" +path="res://.godot/imported/search.svg-ce699cea82128153c676105375a8d6d3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/keychain/assets/search.svg" +dest_files=["res://.godot/imported/search.svg-ce699cea82128153c676105375a8d6d3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/game/addons/keychain/plugin.cfg b/game/addons/keychain/plugin.cfg index 095c8eef..2fd0dfba 100644 --- a/game/addons/keychain/plugin.cfg +++ b/game/addons/keychain/plugin.cfg @@ -3,5 +3,5 @@ name="Keychain" description="A plugin for the Godot Engine that aims to give the player full control over the input actions of the game." author="Orama Interactive" -version="2.0" +version="2.1" script="plugin.gd" diff --git a/game/addons/keychain/plugin.gd.uid b/game/addons/keychain/plugin.gd.uid index a41f2faa..e56d9a45 100644 --- a/game/addons/keychain/plugin.gd.uid +++ b/game/addons/keychain/plugin.gd.uid @@ -1 +1 @@ -uid://f8miskisfxvb +uid://b5i56iyq6ia2e diff --git a/game/addons/keychain/profiles/default.tres b/game/addons/keychain/profiles/default.tres index bd9974c6..de97bd1e 100644 --- a/game/addons/keychain/profiles/default.tres +++ b/game/addons/keychain/profiles/default.tres @@ -1,9 +1,8 @@ [gd_resource type="Resource" script_class="ShortcutProfile" load_steps=2 format=3 uid="uid://df04uev1epmmo"] -[ext_resource type="Script" uid="uid://bqeixyoeq23tm" path="res://addons/keychain/ShortcutProfile.gd" id="1"] +[ext_resource type="Script" uid="uid://bmtkqh6xvat7" path="res://addons/keychain/ShortcutProfile.gd" id="1"] [resource] script = ExtResource("1") name = "Default" customizable = false -bindings = {} diff --git a/game/src/UI/GameMenu/OptionMenu/KeychainShortcutEdit.gd b/game/src/UI/GameMenu/OptionMenu/KeychainShortcutEdit.gd index 29bf7f25..16d5cfdf 100644 --- a/game/src/UI/GameMenu/OptionMenu/KeychainShortcutEdit.gd +++ b/game/src/UI/GameMenu/OptionMenu/KeychainShortcutEdit.gd @@ -1,27 +1,50 @@ extends "res://addons/keychain/ShortcutEdit.gd" +func _add_hotkey(action : StringName, events : Array[InputEvent]) -> void: + Keychain.actions[action] = Keychain.InputAction.new( + action.erase(0, "button_".length()).left(-"_hotkey".length()).capitalize(), + "Hotkeys") + var display_name : String = Keychain.actions[action].display_name + if display_name.begins_with("Mapmode"): + var mapmode_index := display_name.replace("Mapmode", "").to_int() + display_name = tr(GameSingleton.get_mapmode_localisation_key(mapmode_index)) + if mapmode_index <= 10: + display_name = display_name\ + .replace(" Mapmode", "")\ + .replace("Mode de carte ", "")\ + .replace("-Kartenmodus", "")\ + .replace("Modo de mapa de ", "")\ + .replace("Modo mapa de ", "")\ + .replace("Modo mapa ", "") + display_name = tr("Mapmode %s") % display_name.capitalize() + Keychain.actions[action].display_name = display_name + Keychain.selected_profile.bindings[action] = events + func _ready() -> void: + var profile_is_dirty : bool = false + var default := (Keychain.DEFAULT_PROFILE as ShortcutProfile) + # Setup Keychain for Hotkeys for action : StringName in InputMap.get_actions(): if not Keychain.keep_binding_check.call(action): continue - Keychain.actions[action] = Keychain.InputAction.new( - action.erase(0, "button_".length()).left(-"_hotkey".length()).capitalize(), - "Hotkeys") - var display_name : String = Keychain.actions[action].display_name - if display_name.begins_with("Mapmode"): - var mapmode_index := display_name.replace("Mapmode", "").to_int() - display_name = tr(GameSingleton.get_mapmode_localisation_key(mapmode_index)) - if mapmode_index <= 10: - display_name = display_name\ - .replace(" Mapmode", "")\ - .replace("Mode de carte ", "")\ - .replace("-Kartenmodus", "")\ - .replace("Modo de mapa de ", "")\ - .replace("Modo mapa de ", "")\ - .replace("Modo mapa ", "") - display_name = tr("Mapmode %s") % display_name.capitalize() - Keychain.actions[action].display_name = display_name - Keychain.profiles[0].bindings[action] = InputMap.action_get_events(action) + profile_is_dirty = true + default.bindings[action] = InputMap.action_get_events(action) + _add_hotkey(action, default.bindings[action]) + + var has_hotkey_not_loaded_yet := false + for action : StringName in Keychain.selected_profile.bindings: + if InputMap.has_action(action): continue + profile_is_dirty = true + InputMap.add_action(action) + default.bindings[action] = Keychain.selected_profile.bindings[action] + _add_hotkey(action, default.bindings[action]) + has_hotkey_not_loaded_yet = true + + if has_hotkey_not_loaded_yet: + reset_confirmation.dialog_text += "\nWarning: Hotkeys are not loaded, reset may use incorrect default values." + + if profile_is_dirty: + Keychain.selected_profile.save() super._ready()