diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index e699a40ea0c..02352ca808b 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -296,8 +296,9 @@
+
- Emitted when a GraphNode is attempted to be removed from the GraphEdit.
+ Emitted when a GraphNode is attempted to be removed from the GraphEdit. Provides a list of node names to be removed (all selected nodes, excluding nodes without closing button).
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index da1594517fa..08df704f449 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -459,16 +459,22 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
undo_redo->commit_action();
}
-void AnimationNodeBlendTreeEditor::_delete_nodes_request() {
+void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray &p_nodes) {
List to_erase;
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to(graph->get_child(i));
- if (gn) {
- if (gn->is_selected() && gn->is_close_button_visible()) {
- to_erase.push_back(gn->get_name());
+ if (p_nodes.is_empty()) {
+ for (int i = 0; i < graph->get_child_count(); i++) {
+ GraphNode *gn = Object::cast_to(graph->get_child(i));
+ if (gn) {
+ if (gn->is_selected() && gn->is_close_button_visible()) {
+ to_erase.push_back(gn->get_name());
+ }
}
}
+ } else {
+ for (int i = 0; i < p_nodes.size(); i++) {
+ to_erase.push_back(p_nodes[i]);
+ }
}
if (to_erase.is_empty()) {
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 7e96e069c78..b5bf91a1daf 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -103,7 +103,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _open_in_editor(const String &p_which);
void _anim_selected(int p_index, Array p_options, const String &p_node);
void _delete_request(const String &p_which);
- void _delete_nodes_request();
+ void _delete_nodes_request(const TypedArray &p_nodes);
bool _update_filters(const Ref &anode);
void _edit_filters(const String &p_which);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 9ad49e32af8..c5669f3edaf 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -3409,16 +3409,23 @@ void VisualShaderEditor::_delete_node_request(int p_type, int p_node) {
undo_redo->commit_action();
}
-void VisualShaderEditor::_delete_nodes_request() {
+void VisualShaderEditor::_delete_nodes_request(const TypedArray &p_nodes) {
List to_erase;
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to(graph->get_child(i));
- if (gn) {
- if (gn->is_selected() && gn->is_close_button_visible()) {
- to_erase.push_back(gn->get_name().operator String().to_int());
+ if (p_nodes.is_empty()) {
+ // Called from context menu.
+ for (int i = 0; i < graph->get_child_count(); i++) {
+ GraphNode *gn = Object::cast_to(graph->get_child(i));
+ if (gn) {
+ if (gn->is_selected() && gn->is_close_button_visible()) {
+ to_erase.push_back(gn->get_name().operator String().to_int());
+ }
}
}
+ } else {
+ for (int i = 0; i < p_nodes.size(); i++) {
+ to_erase.push_back(p_nodes[i].operator String().to_int());
+ }
}
if (to_erase.is_empty()) {
@@ -4411,7 +4418,7 @@ void VisualShaderEditor::_node_menu_id_pressed(int p_idx) {
_paste_nodes(true, menu_point);
break;
case NodeMenuOptions::DELETE:
- _delete_nodes_request();
+ _delete_nodes_request(TypedArray());
break;
case NodeMenuOptions::DUPLICATE:
_duplicate_nodes();
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 1a3a1d799fa..003c8b15a80 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -346,7 +346,7 @@ class VisualShaderEditor : public VBoxContainer {
void _delete_nodes(int p_type, const List &p_nodes);
void _delete_node_request(int p_type, int p_node);
- void _delete_nodes_request();
+ void _delete_nodes_request(const TypedArray &p_nodes);
void _node_changed(int p_id);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 6f3a361e82f..0ed9a4e9897 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -1343,7 +1343,19 @@ void GraphEdit::gui_input(const Ref &p_ev) {
emit_signal(SNAME("paste_nodes_request"));
accept_event();
} else if (p_ev->is_action("ui_graph_delete")) {
- emit_signal(SNAME("delete_nodes_request"));
+ TypedArray nodes;
+
+ for (int i = 0; i < get_child_count(); i++) {
+ GraphNode *gn = Object::cast_to(get_child(i));
+ if (!gn) {
+ continue;
+ }
+ if (gn->is_selected() && gn->is_close_button_visible()) {
+ nodes.push_back(gn->get_name());
+ }
+ }
+
+ emit_signal(SNAME("delete_nodes_request"), nodes);
accept_event();
}
}
@@ -2290,7 +2302,7 @@ void GraphEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("node_deselected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
- ADD_SIGNAL(MethodInfo("delete_nodes_request"));
+ ADD_SIGNAL(MethodInfo("delete_nodes_request", PropertyInfo(Variant::ARRAY, "nodes", PROPERTY_HINT_ARRAY_TYPE, "StringName")));
ADD_SIGNAL(MethodInfo("begin_node_move"));
ADD_SIGNAL(MethodInfo("end_node_move"));
ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "offset")));