diff --git a/addons/gaea/editor/editor_settings.gd b/addons/gaea/editor/editor_settings.gd index 59c4f7d35..46aba085f 100644 --- a/addons/gaea/editor/editor_settings.gd +++ b/addons/gaea/editor/editor_settings.gd @@ -177,3 +177,31 @@ static func get_preview_max_simulation_size() -> int: if editor_interface.get_editor_settings().has_setting(PREVIEW_MAX_SIMULATION_SIZE): return editor_interface.get_editor_settings().get_setting(PREVIEW_MAX_SIMULATION_SIZE) return PREVIEW_MAX_SIMULATION_SIZE_DEFAULT + + +static func get_file_list_action_shortcut(action: GaeaFileList.Action, shortcut_key: Key) -> Shortcut: + return _get_shortcut("file_list", GaeaFileList.Action.find_key(action), shortcut_key) + + +static func get_node_action_shortcut(action: GaeaGraphEdit.Action, shortcut_key: Key) -> Shortcut: + return _get_shortcut("node_context_menu", GaeaGraphEdit.Action.find_key(action), shortcut_key) + + +static func _get_shortcut(category: String, action_key: String, shortcut_key: Key) -> Shortcut: + var editor_interface = Engine.get_singleton("EditorInterface") + var shortcut_path = StringName(("gaea/%s - %s" % [category.capitalize(), action_key.capitalize()])) + + if editor_interface.get_editor_settings().has_shortcut(shortcut_path): + return editor_interface.get_editor_settings().get_shortcut(shortcut_path) + + var shortcut = Shortcut.new() + var key_event = InputEventKey.new() + key_event.keycode = shortcut_key & KeyModifierMask.KEY_CODE_MASK + key_event.command_or_control_autoremap = shortcut_key & KeyModifierMask.KEY_MASK_CMD_OR_CTRL + key_event.alt_pressed = shortcut_key & KeyModifierMask.KEY_MASK_ALT + key_event.shift_pressed = shortcut_key & KeyModifierMask.KEY_MASK_SHIFT + shortcut.events = [key_event] + + editor_interface.get_editor_settings().add_shortcut(shortcut_path, shortcut) + + return shortcut diff --git a/addons/gaea/editor/file_list/file_context_menu.gd b/addons/gaea/editor/file_list/file_context_menu.gd index 5b7aea6ac..13dec072b 100644 --- a/addons/gaea/editor/file_list/file_context_menu.gd +++ b/addons/gaea/editor/file_list/file_context_menu.gd @@ -3,73 +3,45 @@ class_name GaeaPopupFileContextMenu extends PopupMenu -signal close_file_selected(file: GaeaGraph) -signal close_all_selected -signal close_others_selected(file: GaeaGraph) -signal save_as_selected(file: GaeaGraph) -signal file_saved(file: GaeaGraph) -signal unsaved_file_found(file: GaeaGraph) +@export var file_system_container: GaeaFileList -enum Action { - SAVE, - SAVE_AS, - CLOSE, - CLOSE_ALL, - CLOSE_OTHER, - COPY_PATH, - SHOW_IN_FILESYSTEM, - OPEN_IN_INSPECTOR -} - -var graph: GaeaGraph func _ready() -> void: if is_part_of_edited_scene(): return clear() - add_item("Save File", Action.SAVE) - add_item("Save File As...", Action.SAVE_AS) - add_item("Close", Action.CLOSE) - add_item("Close All", Action.CLOSE_ALL) - add_item("Close Other Tabs", Action.CLOSE_OTHER) - add_separator() - add_item("Copy File Path", Action.COPY_PATH) - add_item("Show in FileSystem", Action.SHOW_IN_FILESYSTEM) - add_item("Open File in Inspector", Action.OPEN_IN_INSPECTOR) - - id_pressed.connect(_on_id_pressed) + _add_menu_item(GaeaFileList.Action.SAVE, "Save", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KeyModifierMask.KEY_MASK_ALT | KEY_S) + _add_menu_item(GaeaFileList.Action.SAVE, "Save As...") + add_separator() + _add_menu_item(GaeaFileList.Action.COPY_PATH, "Copy Graph Path") + _add_menu_item(GaeaFileList.Action.SHOW_IN_FILESYSTEM, "Show in FileSystem") + _add_menu_item(GaeaFileList.Action.OPEN_IN_INSPECTOR, "Open File in Inspector") -func _on_id_pressed(id: int) -> void: - match id: - Action.SAVE: - if graph.resource_path.is_empty(): - unsaved_file_found.emit(graph) - return - - if not graph.is_built_in(): - ResourceSaver.save(graph) - else: - var scene_path := graph.resource_path.get_slice("::", 0) - ResourceSaver.save(load(scene_path)) - # Necessary for open scenes. - EditorInterface.reload_scene_from_path(scene_path) - file_saved.emit(graph) - Action.SAVE_AS: - save_as_selected.emit(graph) - Action.CLOSE: - close_file_selected.emit(graph) - Action.CLOSE_ALL: - close_all_selected.emit() - Action.CLOSE_OTHER: - close_others_selected.emit(graph) - Action.COPY_PATH: - DisplayServer.clipboard_set(graph.resource_path) - Action.SHOW_IN_FILESYSTEM: - if not graph.is_built_in(): - EditorInterface.select_file(graph.resource_path) - else: - EditorInterface.select_file(graph.resource_path.get_slice("::", 0)) - Action.OPEN_IN_INSPECTOR: - EditorInterface.edit_resource(graph) + add_separator() + _add_menu_item(GaeaFileList.Action.CLOSE, "Close", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KEY_W) + _add_menu_item(GaeaFileList.Action.CLOSE_ALL, "Close All") + _add_menu_item(GaeaFileList.Action.CLOSE_OTHER, "Close Other Tabs") + + +func _add_menu_item(id: GaeaFileList.Action, text: String, shortcut_key: Variant = KEY_NONE) -> void: + add_item(tr(text), id) + if shortcut_key is StringName and InputMap.has_action(shortcut_key): + var shortcut = Shortcut.new() + shortcut.events = InputMap.action_get_events(shortcut_key) + set_item_shortcut( + get_item_index(id), + shortcut + ) + elif shortcut_key is Key and shortcut_key != KEY_NONE: + set_item_shortcut( + get_item_index(id), + GaeaEditorSettings.get_file_list_action_shortcut(id, shortcut_key) + ) + + +func _on_about_to_popup() -> void: + for item_index in item_count: + var action: GaeaFileList.Action = get_item_id(item_index) as GaeaFileList.Action + set_item_disabled(item_index, not file_system_container.can_do_action(action)) diff --git a/addons/gaea/editor/file_list/file_system_container.gd b/addons/gaea/editor/file_list/file_system_container.gd index 02d2c976b..f17b01d30 100644 --- a/addons/gaea/editor/file_list/file_system_container.gd +++ b/addons/gaea/editor/file_list/file_system_container.gd @@ -2,12 +2,26 @@ class_name GaeaFileList extends VBoxContainer +enum Action { + NEW_GRAPH, + OPEN, + OPEN_RECENT, + SAVE, + SAVE_AS, + CLOSE, + CLOSE_ALL, + CLOSE_OTHER, + COPY_PATH, + SHOW_IN_FILESYSTEM, + OPEN_IN_INSPECTOR, +} + const GRAPH_ICON := preload("uid://cerisdpavr7v3") @export var graph_edit: GaeaGraphEdit @export var main_editor: GaeaMainEditor -@export var menu_bar: MenuBar +@export var menu_bar: GaeaFileListMenuBar @export var file_list: ItemList @export var context_menu: GaeaPopupFileContextMenu @export var file_dialog: FileDialog @@ -16,28 +30,13 @@ var edited_graphs: Array[EditedGraph] var _current_saving_graph: GaeaGraph = null -func _ready() -> void: - if is_part_of_edited_scene(): - return - - file_list.item_selected.connect(_on_item_selected) - file_list.item_clicked.connect(_on_item_clicked) - - context_menu.close_file_selected.connect(close_file) - context_menu.close_all_selected.connect(close_all) - context_menu.close_others_selected.connect(close_others) - context_menu.save_as_selected.connect(_start_save_as) - context_menu.file_saved.connect(_on_file_saved) - context_menu.unsaved_file_found.connect(_on_unsaved_file_found) - - menu_bar.open_file_selected.connect(open_file) - menu_bar.create_new_graph_selected.connect(_start_new_graph_creation) - file_dialog.file_selected.connect(_on_file_dialog_file_selected) - file_dialog.canceled.connect(_on_file_dialog_canceled) +#region Opening +func open_file_from_path(path: String) -> void: + if not path.is_empty(): + open_file(load(path)) -#region Opening func open_file(graph: GaeaGraph) -> void: if not is_instance_valid(graph): return @@ -57,9 +56,9 @@ func open_file(graph: GaeaGraph) -> void: file_list.set_item_tooltip(idx, graph.resource_path) file_list.select(idx) - _on_item_selected(idx) var edited_graph := EditedGraph.new(graph) edited_graphs.append(edited_graph) + _on_item_selected(idx) edited_graph.dirty_changed.connect(_on_edited_graph_dirty_changed.bind(edited_graph)) #endregion @@ -97,6 +96,21 @@ func _remove(idx: int) -> void: #region Saving +func save(file: GaeaGraph) -> void: + if file.resource_path.is_empty(): + _on_unsaved_file_found(file) + return + + if not file.is_built_in(): + ResourceSaver.save(file) + else: + var scene_path := file.resource_path.get_slice("::", 0) + ResourceSaver.save(load(scene_path)) + # Necessary for open scenes. + EditorInterface.reload_scene_from_path(scene_path) + _on_file_saved(file) + + func _start_save_as(file: GaeaGraph) -> void: file_dialog.title = "Save Graph As..." var path: String = "res://" @@ -145,7 +159,6 @@ func _on_unsaved_file_found(file: GaeaGraph) -> void: func _on_item_clicked(index: int, _at_position: Vector2, mouse_button_index: int) -> void: if mouse_button_index == MOUSE_BUTTON_RIGHT: main_editor.move_popup_at_mouse(context_menu) - context_menu.graph = file_list.get_item_metadata(index) context_menu.popup() elif mouse_button_index == MOUSE_BUTTON_MIDDLE: _remove(index) @@ -159,15 +172,15 @@ func _on_item_selected(index: int) -> void: if metadata is not GaeaGraph or not is_instance_valid(metadata): return - graph_edit.unpopulate() - graph_edit.populate(metadata) + if graph_edit.graph != metadata: + graph_edit.unpopulate() + graph_edit.populate(metadata) var edited: Object = EditorInterface.get_inspector().get_edited_object() if edited is not GaeaGenerator or (edited as GaeaGenerator).graph != metadata: EditorInterface.inspect_object.call_deferred(metadata) - func _on_file_dialog_file_selected(path: String) -> void: var extension: String = path.get_extension() if extension.is_empty(): @@ -206,6 +219,43 @@ func _on_edited_graph_dirty_changed(new_value: bool, edited_graph: EditedGraph) if new_value == true: text += "(*)" file_list.set_item_text(idx, text) + + +func can_do_action(id: Action) -> bool: + match id: + Action.NEW_GRAPH, Action.OPEN: + return true + Action.OPEN_RECENT: + return not menu_bar.is_history_empty() + _: + return not edited_graphs.is_empty() + + +func _on_action_pressed(id: Action) -> void: + match id: + Action.NEW_GRAPH: + _start_new_graph_creation() + Action.OPEN: + EditorInterface.popup_quick_open(open_file_from_path, [&"GaeaGraph"]) + Action.SAVE: + save(graph_edit.graph) + Action.SAVE_AS: + _start_save_as(graph_edit.graph) + Action.CLOSE: + close_file(graph_edit.graph) + Action.CLOSE_ALL: + close_all() + Action.CLOSE_OTHER: + close_others(graph_edit.graph) + Action.COPY_PATH: + DisplayServer.clipboard_set(graph_edit.graph.resource_path) + Action.SHOW_IN_FILESYSTEM: + if not graph_edit.graph.is_built_in(): + EditorInterface.select_file(graph_edit.graph.resource_path) + else: + EditorInterface.select_file(graph_edit.graph.resource_path.get_slice("::", 0)) + Action.OPEN_IN_INSPECTOR: + EditorInterface.edit_resource(graph_edit.graph) #endregion diff --git a/addons/gaea/editor/file_list/menu_bar.gd b/addons/gaea/editor/file_list/menu_bar.gd index 787227472..8f16781ee 100644 --- a/addons/gaea/editor/file_list/menu_bar.gd +++ b/addons/gaea/editor/file_list/menu_bar.gd @@ -1,33 +1,60 @@ @tool +class_name GaeaFileListMenuBar extends MenuBar +signal recent_file_selected(graph: GaeaGraph) -signal open_file_selected(file: GaeaGraph) -signal create_new_graph_selected +@export var file_popup: PopupMenu +@export var recent_files: PopupMenu +@export var edit_popup: PopupMenu +@export var graph_edit: GaeaGraphEdit +@export var file_system_container: GaeaFileList -enum Action { - NEW_GRAPH, - OPEN, - OPEN_RECENT, -} var _history: Array[GaeaGraph] -@onready var file_popup: PopupMenu = $File -@onready var recent_files: PopupMenu = $File/RecentFiles - func _ready() -> void: if is_part_of_edited_scene(): return - file_popup.add_item("New Graph...", Action.NEW_GRAPH) - file_popup.add_item("Open...", Action.OPEN) - file_popup.add_submenu_node_item("Open Recent", recent_files, Action.OPEN_RECENT) - file_popup.id_pressed.connect(_on_id_pressed) - file_popup.about_to_popup.connect(_on_file_item_about_to_popup) + _populate_file_popup_menu() + _populate_edit_popup_menu() + update_menu_enabled_state() + + +#region File menu +func _populate_file_popup_menu() -> void: + _add_file_menu_item(GaeaFileList.Action.NEW_GRAPH, "New Graph...", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KEY_N) + _add_file_menu_item(GaeaFileList.Action.OPEN, "Open...", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KEY_O) + file_popup.add_submenu_node_item("Open Recent", recent_files, GaeaFileList.Action.OPEN_RECENT) + + file_popup.add_separator() + _add_file_menu_item(GaeaFileList.Action.SAVE, "Save", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KeyModifierMask.KEY_MASK_ALT | KEY_S) + _add_file_menu_item(GaeaFileList.Action.SAVE, "Save As...") + + file_popup.add_separator() + _add_file_menu_item(GaeaFileList.Action.COPY_PATH, "Copy Graph Path") + _add_file_menu_item(GaeaFileList.Action.SHOW_IN_FILESYSTEM, "Show in FileSystem") + _add_file_menu_item(GaeaFileList.Action.OPEN_IN_INSPECTOR, "Open File in Inspector") + + file_popup.add_separator() + _add_file_menu_item(GaeaFileList.Action.CLOSE, "Close", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KEY_W) + _add_file_menu_item(GaeaFileList.Action.CLOSE_ALL, "Close All") + _add_file_menu_item(GaeaFileList.Action.CLOSE_OTHER, "Close Other Tabs") + + +func _add_file_menu_item(id: GaeaFileList.Action, text: String, shortcut_key: int = KEY_NONE) -> void: + file_popup.add_item(tr(text), id) + if shortcut_key != KEY_NONE: + file_popup.set_item_shortcut( + file_popup.get_item_index(id), + GaeaEditorSettings.get_file_list_action_shortcut(id, shortcut_key) + ) + - recent_files.id_pressed.connect(_on_recent_files_id_pressed) +func is_history_empty() -> int: + return _history.is_empty() func add_graph_to_history(new_graph: GaeaGraph) -> void: @@ -46,25 +73,71 @@ func add_graph_to_history(new_graph: GaeaGraph) -> void: recent_files.set_item_tooltip(idx, graph.resource_path) -func _on_id_pressed(id: int) -> void: - match id: - Action.NEW_GRAPH: - create_new_graph_selected.emit() - Action.OPEN: - EditorInterface.popup_quick_open(_on_file_chosen_to_open, [&"GaeaGraph"]) - - -func _on_file_chosen_to_open(path: String) -> void: - if path.is_empty(): - return - open_file_selected.emit(load(path)) - - func _on_recent_files_id_pressed(id: int) -> void: - open_file_selected.emit( + recent_file_selected.emit( recent_files.get_item_metadata(recent_files.get_item_index(id)) ) func _on_file_item_about_to_popup() -> void: - file_popup.set_item_disabled(2, _history.is_empty()) + file_popup.set_item_disabled(file_popup.get_item_index(GaeaFileList.Action.OPEN_RECENT), _history.is_empty()) +#endregion + +#region Edit menu +func _populate_edit_popup_menu() -> void: + _add_edit_menu_item(GaeaGraphEdit.Action.ADD, "Add Node", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KEY_A) + edit_popup.add_separator() + _add_edit_menu_item(GaeaGraphEdit.Action.CUT, "Cut", &"ui_cut") + _add_edit_menu_item(GaeaGraphEdit.Action.COPY, "Copy", &"ui_copy") + _add_edit_menu_item(GaeaGraphEdit.Action.PASTE, "Paste", &"ui_paste") + edit_popup.add_separator() + _add_edit_menu_item(GaeaGraphEdit.Action.SELECT_ALL, "Select All") + _add_edit_menu_item(GaeaGraphEdit.Action.DUPLICATE, "Duplicate Selection", &"ui_graph_duplicate") + _add_edit_menu_item(GaeaGraphEdit.Action.DELETE, "Delete Selection", &"ui_graph_delete") + _add_edit_menu_item(GaeaGraphEdit.Action.CLEAR_BUFFER, "Clear Copy Buffer") + + edit_popup.add_separator() + _add_edit_menu_item( + GaeaGraphEdit.Action.COPY_TO_CLIPBOARD, "Copy to Clipboard", + KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KeyModifierMask.KEY_MASK_SHIFT | KEY_C + ) + _add_edit_menu_item( + GaeaGraphEdit.Action.PASTE_FROM_CLIPBOARD, "Paste from Clipboard", + KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KeyModifierMask.KEY_MASK_SHIFT | KEY_V + ) + + edit_popup.add_separator() + _add_edit_menu_item(GaeaGraphEdit.Action.GROUP_IN_FRAME, "Group Selection in New Frame", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KEY_G) + + _add_edit_menu_item(GaeaGraphEdit.Action.DETACH, "Detach from Parent Frame") + + +func _add_edit_menu_item(id: GaeaGraphEdit.Action, text: String, shortcut_key: Variant = KEY_NONE) -> void: + edit_popup.add_item(tr(text), id) + if shortcut_key is StringName and InputMap.has_action(shortcut_key): + var shortcut = Shortcut.new() + shortcut.events = InputMap.action_get_events(shortcut_key) + edit_popup.set_item_shortcut( + edit_popup.get_item_index(id), + shortcut + ) + elif shortcut_key is Key and shortcut_key != KEY_NONE: + edit_popup.set_item_shortcut( + edit_popup.get_item_index(id), + GaeaEditorSettings.get_node_action_shortcut(id, shortcut_key) + ) +#endregion + + +func update_menu_enabled_state() -> void: + for item_index in edit_popup.item_count: + var action: GaeaGraphEdit.Action = edit_popup.get_item_id(item_index) as GaeaGraphEdit.Action + var disabled: bool = not graph_edit.can_do_action(action) + edit_popup.set_item_disabled(item_index, disabled) + edit_popup.set_item_shortcut_disabled(item_index, disabled) + + for item_index in file_popup.item_count: + var action: GaeaFileList.Action = file_popup.get_item_id(item_index) as GaeaFileList.Action + var disabled: bool = not file_system_container.can_do_action(action) + file_popup.set_item_disabled(item_index, disabled) + file_popup.set_item_shortcut_disabled(item_index, disabled) diff --git a/addons/gaea/editor/graph_editor/graph_edit.gd b/addons/gaea/editor/graph_editor/graph_edit.gd index 21405d3ff..3a8dca658 100644 --- a/addons/gaea/editor/graph_editor/graph_edit.gd +++ b/addons/gaea/editor/graph_editor/graph_edit.gd @@ -2,9 +2,32 @@ class_name GaeaGraphEdit extends GraphEdit +signal graph_changed() +signal node_selection_changed() signal copy_to_clipboard_request() signal paste_from_clipboard_request() +enum Action { + ADD, + CUT, + COPY, + PASTE, + SELECT_ALL, + DUPLICATE, + DELETE, + CLEAR_BUFFER, + RENAME, + TOGGLE_TINT, + TINT, + GROUP_IN_FRAME, + DETACH, + TOGGLE_AUTO_SHRINK, + OPEN_IN_INSPECTOR, + COPY_TO_CLIPBOARD, + PASTE_FROM_CLIPBOARD, +} + + @export var main_editor: GaeaMainEditor @export var bottom_note_label: RichTextLabel @@ -14,11 +37,15 @@ var attached_elements: Dictionary[StringName, StringName] ## Currently edited resource, use [method populate] to change the graph var graph: GaeaGraph : set(value): + if graph == value: + return graph = value if not is_instance_valid(graph): hide() else: show() + graph_changed.emit() + ## Buffer used to store copied nodes var copy_buffer: GaeaNodesCopy @@ -253,7 +280,8 @@ func _add_node(resource: GaeaNodeResource, local_grid_position: Vector2) -> Grap func _on_delete_nodes_request(nodes: Array[StringName]) -> void: - delete_nodes(nodes) + if can_do_action(Action.DELETE): + delete_nodes(nodes) func delete_nodes(nodes: Array[StringName]) -> void: @@ -695,22 +723,26 @@ func _get_copy_data(nodes: Array[GraphElement]) -> GaeaNodesCopy: func _on_duplicate_nodes_request() -> void: - var copy_data := _get_copy_data(get_selected()) - _copy_nodes(copy_data) - _paste_nodes(copy_data.get_origin() + Vector2(snapping_distance, snapping_distance)) + if can_do_action(Action.DUPLICATE): + var copy_data := _get_copy_data(get_selected()) + _copy_nodes(copy_data) + _paste_nodes(copy_data.get_origin() + Vector2(snapping_distance, snapping_distance)) func _on_copy_nodes_request() -> void: - _copy_nodes(_get_copy_data(get_selected())) + if can_do_action(Action.COPY): + _copy_nodes(_get_copy_data(get_selected())) func _on_paste_nodes_request() -> void: - _paste_nodes(local_to_grid(get_local_mouse_position())) + if can_do_action(Action.PASTE): + _paste_nodes(local_to_grid(get_local_mouse_position())) func _on_cut_nodes_request() -> void: - _copy_nodes(_get_copy_data(get_selected())) - delete_nodes(get_selected_names()) + if can_do_action(Action.CUT): + _copy_nodes(_get_copy_data(get_selected())) + delete_nodes(get_selected_names()) #endregion @@ -798,3 +830,159 @@ func _on_paste_from_clipboard_request() -> void: _paste_nodes(local_to_grid(get_local_mouse_position()), copy_data) elif copy_data is String: EditorInterface.get_editor_toaster().push_toast(copy_data, EditorToaster.SEVERITY_ERROR) + + +func _on_node_deselected(_node: Node) -> void: + node_selection_changed.emit() + + +func _on_node_selected(_node: Node) -> void: + node_selection_changed.emit() + + +func can_do_action(id: Action) -> bool: + match id: + Action.ADD, Action.SELECT_ALL, Action.PASTE_FROM_CLIPBOARD: + return true + Action.COPY, Action.CUT, Action.DELETE, Action.DUPLICATE, Action.GROUP_IN_FRAME, Action.DETACH, Action.COPY_TO_CLIPBOARD: + return not get_selected().is_empty() + Action.RENAME: + return get_selected().size() == 1 + Action.PASTE, Action.CLEAR_BUFFER: + return is_instance_valid(copy_buffer) + Action.TINT, Action.TOGGLE_TINT, Action.TOGGLE_AUTO_SHRINK: + var selected: Array = get_selected() + return selected.size() == 1 and selected.front() is GaeaGraphFrame + Action.OPEN_IN_INSPECTOR: + var selected: Array = get_selected() + return selected.size() == 1 and selected.front() is GaeaNodeParameter + return false + + +func _on_action_pressed(id: Action) -> void: + match id: + Action.ADD: + main_editor.popup_create_node_request.emit() + Action.COPY: + copy_nodes_request.emit() + Action.PASTE: + paste_nodes_request.emit() + Action.SELECT_ALL: + for node: Node in get_children(): + if node is GraphElement: + node.selected = true + Action.DUPLICATE: + duplicate_nodes_request.emit() + Action.CUT: + cut_nodes_request.emit() + Action.DELETE: + delete_nodes_request.emit(get_selected_names()) + Action.CLEAR_BUFFER: + copy_buffer = null + Action.RENAME: + var selected: Array = get_selected() + var node: GraphElement = selected.front() + if node is GaeaGraphFrame: + node.start_rename(owner) + Action.TINT: + var selected: Array = get_selected() + var node: GraphElement = selected.front() + if node is GaeaGraphFrame: + node.start_tint_color_change(owner) + Action.TOGGLE_TINT: + var selected: Array = get_selected() + var node: GraphElement = selected.front() + if node is GaeaGraphFrame: + var toggled: bool = not node.is_tint_color_enabled() + node.set_tint_color_enabled(toggled) + graph.set_node_data_value(node.id, &"tint_color_enabled", toggled) + Action.TOGGLE_AUTO_SHRINK: + var selected: Array = get_selected() + var node: GraphElement = selected.front() + if node is GaeaGraphFrame: + var toggled: bool = not node.is_autoshrink_enabled() + node.set_autoshrink_enabled(toggled) + # The node data for the autoshrink is set from a GraphFrame signal + Action.GROUP_IN_FRAME: + var selected: Array[StringName] = get_selected_names() + _group_nodes_in_frame(selected) + Action.DETACH: + var selected: Array = get_selected() + for node: GraphElement in selected: + if attached_elements.has(node.name): + detach_element_from_frame(node.name) + Action.OPEN_IN_INSPECTOR: + var node: GaeaGraphNode = get_selected().front() + var resource: GaeaNodeResource = node.resource + if resource is GaeaNodeParameter: + var parameter: Dictionary = graph.get_parameter_dictionary(node.get_arg_value("name")) + var value: Variant = parameter.get("value") + if value is Resource and is_instance_valid(value): + EditorInterface.edit_resource(value) + Action.COPY_TO_CLIPBOARD: + copy_to_clipboard_request.emit() + Action.PASTE_FROM_CLIPBOARD: + paste_from_clipboard_request.emit() + + +func _get_node_frame_parents_list(node_name: StringName) -> Array[StringName]: + var list: Array[StringName] = [] + var loop_limit: int = 50 + while loop_limit > 0: + loop_limit -= 1 + if attached_elements.has(node_name): + node_name = attached_elements.get(node_name) + list.append(node_name) + else: + list.append(&"null") + break + return list + + +func _group_nodes_in_frame(nodes: Array[StringName]) -> void: + var front_node: StringName = nodes.front() + var front_frame_tree: Array[StringName] = _get_node_frame_parents_list(front_node) + front_frame_tree.reverse() + for other_node: StringName in nodes: + var other_frame_tree: Array[StringName] = _get_node_frame_parents_list(other_node) + other_frame_tree.reverse() + for i in range(0, mini(front_frame_tree.size(), other_frame_tree.size())): + if not front_frame_tree[i] == other_frame_tree[i]: + front_frame_tree.resize(i) + + var matching_parent: StringName = front_frame_tree.back() + var things_to_group: Array[StringName] = [] + var parent_name: StringName + for node_name: StringName in nodes: + var loop_limit: int = 50 + while loop_limit > 0: + loop_limit -= 1 + parent_name = attached_elements.get(node_name, &"null") + if parent_name == matching_parent: + if not things_to_group.has(node_name): + things_to_group.append(node_name) + break + node_name = parent_name + + var positions: Array = things_to_group.map(func(node_name: StringName): + return (get_node(NodePath(node_name)) as GraphElement).position + ) + var frame_position: Vector2 = positions.reduce(func(a: Vector2, b: Vector2): + return a.min(b), positions.front() + ) + var new_frame_id: int = graph.add_frame(frame_position) + var new_frame: Node = instantiate_node(new_frame_id) + var new_frame_name: StringName = new_frame.name + + if matching_parent != &"null": + attach_graph_element_to_frame(new_frame_name, matching_parent) + _on_element_attached_to_frame(new_frame_name, matching_parent) + + for node_name: StringName in things_to_group: + detach_element_from_frame(node_name) + + for node_name in things_to_group: + attach_graph_element_to_frame(node_name, new_frame_name) + _on_element_attached_to_frame(node_name, new_frame_name) + + new_frame.selected = true diff --git a/addons/gaea/editor/graph_editor/main_editor.gd b/addons/gaea/editor/graph_editor/main_editor.gd index b2c358608..ba3da7d30 100644 --- a/addons/gaea/editor/graph_editor/main_editor.gd +++ b/addons/gaea/editor/graph_editor/main_editor.gd @@ -41,8 +41,6 @@ func _ready() -> void: popup_create_node_and_connect_node_request.connect(create_node_popup._on_popup_create_node_and_connect_node_request) special_node_selected_for_creation.connect(create_node_popup._on_special_node_selected_for_creation) - popup_node_context_menu_at_mouse_request.connect(node_context_menu._on_popup_node_context_menu_at_mouse_request) - popup_link_context_menu_at_mouse_request.connect(link_context_menu._on_popup_link_context_menu_at_mouse_request) diff --git a/addons/gaea/editor/graph_editor/node_context_menu.gd b/addons/gaea/editor/graph_editor/node_context_menu.gd index 8e52e80cc..152fce4f6 100644 --- a/addons/gaea/editor/graph_editor/node_context_menu.gd +++ b/addons/gaea/editor/graph_editor/node_context_menu.gd @@ -2,24 +2,6 @@ class_name GaeaPopupNodeContextMenu extends PopupMenu -enum Action { - ADD, - CUT, - COPY, - PASTE, - DUPLICATE, - DELETE, - CLEAR_BUFFER, - RENAME, - ENABLE_TINT, - TINT, - GROUP_IN_FRAME, - DETACH, - ENABLE_AUTO_SHRINK, - OPEN_IN_INSPECTOR, - COPY_TO_CLIPBOARD, - PASTE_FROM_CLIPBOARD, -} @export var main_editor: GaeaMainEditor @export var graph_edit: GaeaGraphEdit @@ -29,199 +11,93 @@ func _ready() -> void: if is_part_of_edited_scene(): return hide() - id_pressed.connect(_on_id_pressed) + + +func _on_popup_node_context_menu_at_mouse_request(selected_nodes: Array) -> void: + clear() + populate(selected_nodes) + main_editor.node_creation_target = graph_edit.get_local_mouse_position() + main_editor.move_popup_at_mouse(self) + popup() func populate(selected: Array) -> void: - add_item("Add Node", Action.ADD) + _add_menu_item(GaeaGraphEdit.Action.ADD, "Add Node", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KEY_A) add_separator() - add_item("Copy", Action.COPY) - add_item("Paste", Action.PASTE) - add_item("Duplicate", Action.DUPLICATE) - add_item("Cut", Action.CUT) - add_item("Delete", Action.DELETE) - add_item("Clear Copy Buffer", Action.CLEAR_BUFFER) + _add_menu_item(GaeaGraphEdit.Action.CUT, "Cut", &"ui_cut") + _add_menu_item(GaeaGraphEdit.Action.COPY, "Copy", &"ui_copy") + _add_menu_item(GaeaGraphEdit.Action.PASTE, "Paste", &"ui_paste") add_separator() - add_item("Copy to Clipboard", Action.COPY_TO_CLIPBOARD) - add_item("Paste from Clipboard", Action.PASTE_FROM_CLIPBOARD) + _add_menu_item(GaeaGraphEdit.Action.SELECT_ALL, "Select All") + _add_menu_item(GaeaGraphEdit.Action.DUPLICATE, "Duplicate Selection", &"ui_graph_duplicate") + _add_menu_item(GaeaGraphEdit.Action.DELETE, "Delete Selection", &"ui_graph_delete") + _add_menu_item(GaeaGraphEdit.Action.CLEAR_BUFFER, "Clear Copy Buffer") - if not is_instance_valid(graph_edit.copy_buffer): - set_item_disabled(get_item_index(Action.PASTE), true) - set_item_disabled(get_item_index(Action.CLEAR_BUFFER), true) + add_separator() + _add_menu_item( + GaeaGraphEdit.Action.COPY_TO_CLIPBOARD, "Copy to Clipboard", + KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KeyModifierMask.KEY_MASK_SHIFT | KEY_C + ) + _add_menu_item( + GaeaGraphEdit.Action.PASTE_FROM_CLIPBOARD, "Paste from Clipboard", + KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KeyModifierMask.KEY_MASK_SHIFT | KEY_V + ) if not selected.is_empty(): add_separator() - add_item("Group in New Frame", Action.GROUP_IN_FRAME) + _add_menu_item(GaeaGraphEdit.Action.GROUP_IN_FRAME, "Group in New Frame", KeyModifierMask.KEY_MASK_CMD_OR_CTRL | KEY_G) for node: GraphElement in selected: if graph_edit.attached_elements.has(node.name): - add_item("Detach from Parent Frame", Action.DETACH) + _add_menu_item(GaeaGraphEdit.Action.DETACH, "Detach from Parent Frame") break - if selected.is_empty(): - set_item_disabled(get_item_index(Action.DUPLICATE), true) - set_item_disabled(get_item_index(Action.COPY), true) - set_item_disabled(get_item_index(Action.CUT), true) - set_item_disabled(get_item_index(Action.DELETE), true) - set_item_disabled(get_item_index(Action.COPY_TO_CLIPBOARD), true) - return - if selected.front() is GaeaGraphFrame and selected.size() == 1: - add_separator() - add_item("Rename Frame", Action.RENAME) - add_check_item("Enable Auto Shrink", Action.ENABLE_AUTO_SHRINK) - add_check_item("Enable Tint Color", Action.ENABLE_TINT) - add_item("Set Tint Color", Action.TINT) - set_item_disabled(get_item_index(Action.TINT), not selected.front().tint_color_enabled) - - set_item_checked(get_item_index(Action.ENABLE_TINT), selected.front().tint_color_enabled) - set_item_checked( - get_item_index(Action.ENABLE_AUTO_SHRINK), selected.front().autoshrink_enabled - ) - size = get_contents_minimum_size() - - if selected.front() is GaeaGraphNode and selected.size() == 1: - var node: GaeaGraphNode = selected.front() - var resource: GaeaNodeResource = node.resource - if resource is GaeaNodeParameter: - var parameter: Dictionary = graph_edit.graph.get_parameter_dictionary(node.get_arg_value("name")) - if parameter.get("value") is Resource: - add_separator() - add_item("Open In Inspector", Action.OPEN_IN_INSPECTOR) - - -func _on_id_pressed(id: int) -> void: - var idx: int = get_item_index(id) - match id: - Action.ADD: - main_editor.popup_create_node_request.emit() - Action.COPY: - graph_edit.copy_nodes_request.emit() - Action.PASTE: - graph_edit.paste_nodes_request.emit() - Action.DUPLICATE: - graph_edit.duplicate_nodes_request.emit() - Action.CUT: - graph_edit.cut_nodes_request.emit() - Action.DELETE: - graph_edit.delete_nodes_request.emit(graph_edit.get_selected_names()) - Action.CLEAR_BUFFER: - graph_edit.copy_buffer = null - - Action.RENAME: - var selected: Array = graph_edit.get_selected() - var node: GraphElement = selected.front() - if node is GaeaGraphFrame: - node.start_rename(owner) - - Action.TINT: - var selected: Array = graph_edit.get_selected() - var node: GraphElement = selected.front() - if node is GaeaGraphFrame: - node.start_tint_color_change(owner) - Action.ENABLE_TINT: - set_item_checked(idx, not is_item_checked(idx)) - var selected: Array = graph_edit.get_selected() - var node: GraphElement = selected.front() - if node is GaeaGraphFrame: - node.set_tint_color_enabled(is_item_checked(idx)) - graph_edit.graph.set_node_data_value(node.id, &"tint_color_enabled", is_item_checked(idx)) - Action.ENABLE_AUTO_SHRINK: - set_item_checked(idx, not is_item_checked(idx)) - var selected: Array = graph_edit.get_selected() - var node: GraphElement = selected.front() - if node is GaeaGraphFrame: - node.set_autoshrink_enabled(is_item_checked(idx)) - Action.GROUP_IN_FRAME: - var selected: Array[StringName] = graph_edit.get_selected_names() - _group_nodes_in_frame(selected) - Action.COPY_TO_CLIPBOARD: - graph_edit.copy_to_clipboard_request.emit() - Action.PASTE_FROM_CLIPBOARD: - graph_edit.paste_from_clipboard_request.emit() - Action.DETACH: - var selected: Array = graph_edit.get_selected() - for node: GraphElement in selected: - if graph_edit.attached_elements.has(node.name): - graph_edit.detach_element_from_frame(node.name) - Action.OPEN_IN_INSPECTOR: - var node: GaeaGraphNode = graph_edit.get_selected().front() + if selected.size() == 1: + if selected.front() is GaeaGraphFrame: + add_separator() + add_item("Rename Frame", GaeaGraphEdit.Action.RENAME) + add_check_item("Enable Auto Shrink", GaeaGraphEdit.Action.TOGGLE_AUTO_SHRINK) + add_check_item("Enable Tint Color", GaeaGraphEdit.Action.TOGGLE_TINT) + add_item("Set Tint Color", GaeaGraphEdit.Action.TINT) + + set_item_checked(get_item_index(GaeaGraphEdit.Action.TOGGLE_TINT), selected.front().tint_color_enabled) + set_item_checked( + get_item_index(GaeaGraphEdit.Action.TOGGLE_AUTO_SHRINK), selected.front().autoshrink_enabled + ) + size = get_contents_minimum_size() + + if selected.front() is GaeaGraphNode: + var node: GaeaGraphNode = selected.front() + var resource: GaeaNodeResource = node.resource if resource is GaeaNodeParameter: var parameter: Dictionary = graph_edit.graph.get_parameter_dictionary(node.get_arg_value("name")) - var value: Variant = parameter.get("value") - if value is Resource and is_instance_valid(value): - EditorInterface.edit_resource(value) - - -func _get_node_frame_parents_list(node_name: StringName) -> Array[StringName]: - var list: Array[StringName] = [] - var loop_limit: int = 50 - while loop_limit > 0: - loop_limit -= 1 - if graph_edit.attached_elements.has(node_name): - node_name = graph_edit.attached_elements.get(node_name) - list.append(node_name) - else: - list.append(&"null") - break - return list - -func _on_popup_node_context_menu_at_mouse_request(selected_nodes: Array) -> void: - clear() - populate(selected_nodes) - main_editor.node_creation_target = graph_edit.get_local_mouse_position() - main_editor.move_popup_at_mouse(self) - popup() + if parameter.get("value") is Resource: + add_separator() + add_item("Open In Inspector", GaeaGraphEdit.Action.OPEN_IN_INSPECTOR) + for item_idx: int in item_count: + var action: GaeaGraphEdit.Action = get_item_id(item_idx) + set_item_disabled(item_idx, not graph_edit.can_do_action(action)) -func _group_nodes_in_frame(nodes: Array[StringName]) -> void: - var front_node: StringName = nodes.front() - var front_frame_tree: Array[StringName] = _get_node_frame_parents_list(front_node) - front_frame_tree.reverse() - for other_node: StringName in nodes: - var other_frame_tree: Array[StringName] = _get_node_frame_parents_list(other_node) - other_frame_tree.reverse() - for i in range(0, mini(front_frame_tree.size(), other_frame_tree.size())): - if not front_frame_tree[i] == other_frame_tree[i]: - front_frame_tree.resize(i) - - var matching_parent: StringName = front_frame_tree.back() - var things_to_group: Array[StringName] = [] - var parent_name: StringName - for node_name: StringName in nodes: - var loop_limit: int = 50 - while loop_limit > 0: - loop_limit -= 1 - parent_name = graph_edit.attached_elements.get(node_name, &"null") - if parent_name == matching_parent: - if not things_to_group.has(node_name): - things_to_group.append(node_name) - break - node_name = parent_name - - var positions: Array = things_to_group.map(func(node_name: StringName): - return (graph_edit.get_node(NodePath(node_name)) as GraphElement).position - ) - var frame_position: Vector2 = positions.reduce(func(a: Vector2, b: Vector2): - return a.min(b), positions.front() - ) - var new_frame_id: int = graph_edit.graph.add_frame(frame_position) - var new_frame: Node = graph_edit.instantiate_node(new_frame_id) - var new_frame_name: StringName = new_frame.name - if matching_parent != &"null": - graph_edit.attach_graph_element_to_frame(new_frame_name, matching_parent) - graph_edit._on_element_attached_to_frame(new_frame_name, matching_parent) - for node_name: StringName in things_to_group: - graph_edit.detach_element_from_frame(node_name) - for node_name in things_to_group: - graph_edit.attach_graph_element_to_frame(node_name, new_frame_name) - graph_edit._on_element_attached_to_frame(node_name, new_frame_name) - - new_frame.selected = true +func _add_menu_item(id: GaeaGraphEdit.Action, text: String, shortcut_key: Variant = KEY_NONE) -> void: + add_item(tr(text), id) + if shortcut_key is StringName and InputMap.has_action(shortcut_key): + var shortcut = Shortcut.new() + shortcut.events = InputMap.action_get_events(shortcut_key) + set_item_shortcut( + get_item_index(id), + shortcut + ) + elif shortcut_key is Key and shortcut_key != KEY_NONE: + set_item_shortcut( + get_item_index(id), + GaeaEditorSettings.get_node_action_shortcut(id, shortcut_key) + ) diff --git a/addons/gaea/editor/panel/panel.tscn b/addons/gaea/editor/panel/panel.tscn index cf57642bc..3e0b715f9 100644 --- a/addons/gaea/editor/panel/panel.tscn +++ b/addons/gaea/editor/panel/panel.tscn @@ -40,24 +40,33 @@ file_list = NodePath("FileList") context_menu = NodePath("FileList/ContextMenu") file_dialog = NodePath("FileDialog") -[node name="MenuBar" type="MenuBar" parent="FileSystemContainer" unique_id=715932684] +[node name="MenuBar" type="MenuBar" parent="FileSystemContainer" unique_id=715932684 node_paths=PackedStringArray("shortcut_context", "file_popup", "recent_files", "edit_popup", "graph_edit", "file_system_container")] layout_mode = 2 +shortcut_context = NodePath("../..") theme_type_variation = &"FlatButton" script = ExtResource("2_ce5k6") +file_popup = NodePath("File") +recent_files = NodePath("File/RecentFiles") +edit_popup = NodePath("Edit") +graph_edit = NodePath("../../MainEditor/GraphEdit") +file_system_container = NodePath("..") [node name="File" type="PopupMenu" parent="FileSystemContainer/MenuBar" unique_id=1123094324] oversampling_override = 1.0 [node name="RecentFiles" type="PopupMenu" parent="FileSystemContainer/MenuBar/File" unique_id=2123746125] +[node name="Edit" type="PopupMenu" parent="FileSystemContainer/MenuBar" unique_id=916976544] + [node name="FileList" type="ItemList" parent="FileSystemContainer" unique_id=572815294] layout_mode = 2 size_flags_vertical = 3 allow_reselect = true allow_rmb_select = true -[node name="ContextMenu" type="PopupMenu" parent="FileSystemContainer/FileList" unique_id=193406563] +[node name="ContextMenu" type="PopupMenu" parent="FileSystemContainer/FileList" unique_id=193406563 node_paths=PackedStringArray("file_system_container")] script = ExtResource("3_gbl2m") +file_system_container = NodePath("../..") [node name="FileDialog" type="FileDialog" parent="FileSystemContainer" unique_id=64284388] title = "Save Graph As..." @@ -248,20 +257,6 @@ text = "Cancel" [node name="NodeContextMenu" type="PopupMenu" parent="MainEditor" unique_id=802440902 node_paths=PackedStringArray("main_editor", "graph_edit")] oversampling_override = 1.0 size = Vector2i(100, 124) -item_count = 6 -item_0/text = "Add Node" -item_0/id = 0 -item_1/id = 1 -item_1/separator = true -item_2/text = "Delete" -item_2/id = 2 -item_3/id = 9999 -item_3/separator = true -item_4/text = "Rename" -item_4/id = 3 -item_4/disabled = true -item_5/text = "Set Color" -item_5/id = 5 script = ExtResource("4_vtsfx") main_editor = NodePath("..") graph_edit = NodePath("../GraphEdit") @@ -269,13 +264,22 @@ graph_edit = NodePath("../GraphEdit") [node name="LinkContextMenu" type="PopupMenu" parent="MainEditor" unique_id=566265106 node_paths=PackedStringArray("main_editor")] oversampling_override = 1.0 size = Vector2i(106, 100) -item_count = 1 -item_0/text = "Disconnect" -item_0/id = 0 script = ExtResource("7_dhpru") main_editor = NodePath("..") +[connection signal="recent_file_selected" from="FileSystemContainer/MenuBar" to="FileSystemContainer" method="open_file"] +[connection signal="about_to_popup" from="FileSystemContainer/MenuBar/File" to="FileSystemContainer/MenuBar" method="_on_file_item_about_to_popup"] +[connection signal="id_pressed" from="FileSystemContainer/MenuBar/File" to="FileSystemContainer" method="_on_action_pressed"] +[connection signal="id_pressed" from="FileSystemContainer/MenuBar/File/RecentFiles" to="FileSystemContainer/MenuBar" method="_on_recent_files_id_pressed"] +[connection signal="id_pressed" from="FileSystemContainer/MenuBar/Edit" to="MainEditor/GraphEdit" method="_on_action_pressed"] +[connection signal="item_clicked" from="FileSystemContainer/FileList" to="FileSystemContainer" method="_on_item_clicked"] +[connection signal="item_selected" from="FileSystemContainer/FileList" to="FileSystemContainer" method="_on_item_selected"] +[connection signal="about_to_popup" from="FileSystemContainer/FileList/ContextMenu" to="FileSystemContainer/FileList/ContextMenu" method="_on_about_to_popup"] +[connection signal="id_pressed" from="FileSystemContainer/FileList/ContextMenu" to="FileSystemContainer" method="_on_action_pressed"] +[connection signal="canceled" from="FileSystemContainer/FileDialog" to="FileSystemContainer" method="_on_file_dialog_canceled"] +[connection signal="file_selected" from="FileSystemContainer/FileDialog" to="FileSystemContainer" method="_on_file_dialog_file_selected"] [connection signal="about_popup_request" from="MainEditor" to="MainEditor/AboutWindow" method="_on_main_editor_about_popup_request"] +[connection signal="popup_node_context_menu_at_mouse_request" from="MainEditor" to="MainEditor/NodeContextMenu" method="_on_popup_node_context_menu_at_mouse_request"] [connection signal="visibility_changed" from="MainEditor" to="MainEditor/GraphEdit" method="_on_main_editor_visibility_changed"] [connection signal="connection_from_empty" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_connection_from_empty"] [connection signal="connection_request" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_connection_request"] @@ -285,8 +289,12 @@ main_editor = NodePath("..") [connection signal="delete_nodes_request" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_delete_nodes_request"] [connection signal="disconnection_request" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_disconnection_request"] [connection signal="duplicate_nodes_request" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_duplicate_nodes_request"] +[connection signal="graph_changed" from="MainEditor/GraphEdit" to="FileSystemContainer/MenuBar" method="update_menu_enabled_state"] [connection signal="graph_elements_linked_to_frame_request" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_graph_elements_linked_to_frame_request"] [connection signal="gui_input" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_gui_input"] +[connection signal="node_deselected" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_node_deselected"] +[connection signal="node_selected" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_node_selected"] +[connection signal="node_selection_changed" from="MainEditor/GraphEdit" to="FileSystemContainer/MenuBar" method="update_menu_enabled_state"] [connection signal="paste_nodes_request" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_paste_nodes_request"] [connection signal="scroll_offset_changed" from="MainEditor/GraphEdit" to="MainEditor/GraphEdit" method="_on_scroll_offset_changed"] [connection signal="text_changed" from="MainEditor/CreateNodePopup/MainContentContainer/VBox/SearchContainer/SearchBar" to="MainEditor/CreateNodePopup/MainContentContainer/VBox/CreateNodeTree" method="_on_search_bar_text_changed"] @@ -297,3 +305,4 @@ main_editor = NodePath("..") [connection signal="item_selected" from="MainEditor/CreateNodePopup/MainContentContainer/VBox/CreateNodeTree" to="MainEditor/CreateNodePopup/MainContentContainer/VBox/CreateNodeTree" method="_on_item_selected"] [connection signal="nothing_selected" from="MainEditor/CreateNodePopup/MainContentContainer/VBox/CreateNodeTree" to="MainEditor/CreateNodePopup/MainContentContainer/VBox/CreateNodeTree" method="_on_nothing_selected"] [connection signal="pressed" from="MainEditor/CreateNodePopup/MainContentContainer/VBox/HBoxContainer/CreateButton" to="MainEditor/CreateNodePopup/MainContentContainer/VBox/CreateNodeTree" method="_on_create_button_pressed"] +[connection signal="id_pressed" from="MainEditor/NodeContextMenu" to="MainEditor/GraphEdit" method="_on_action_pressed"]