diff --git a/editor/animation/animation_blend_space_1d_editor.cpp b/editor/animation/animation_blend_space_1d_editor.cpp index 9e09ab6cc85..970678320eb 100644 --- a/editor/animation/animation_blend_space_1d_editor.cpp +++ b/editor/animation/animation_blend_space_1d_editor.cpp @@ -143,6 +143,11 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Refpush_item(blend_space.ptr(), "", true); + } } if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) { @@ -529,7 +534,11 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() { undo_redo->add_undo_method(this, "_update_space"); undo_redo->commit_action(); + // Return selection to host BlendSpace1D node. + EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true); + updating = false; + _update_tool_erase(); blend_space_draw->queue_redraw(); } diff --git a/editor/animation/animation_blend_space_2d_editor.cpp b/editor/animation/animation_blend_space_2d_editor.cpp index 17331d02c0f..40d49fb8578 100644 --- a/editor/animation/animation_blend_space_2d_editor.cpp +++ b/editor/animation/animation_blend_space_2d_editor.cpp @@ -203,6 +203,11 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Refpush_item(blend_space.ptr(), "", true); + } } if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { @@ -727,7 +732,12 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() { undo_redo->add_do_method(this, "_update_space"); undo_redo->add_undo_method(this, "_update_space"); undo_redo->commit_action(); + + // Return selection to host BlendSpace2D node. + EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true); + updating = false; + _update_tool_erase(); blend_space_draw->queue_redraw(); } else if (selected_triangle != -1) { @@ -739,7 +749,11 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() { undo_redo->add_do_method(this, "_update_space"); undo_redo->add_undo_method(this, "_update_space"); undo_redo->commit_action(); + + selected_triangle = -1; + updating = false; + _update_tool_erase(); blend_space_draw->queue_redraw(); } diff --git a/editor/animation/animation_blend_tree_editor_plugin.cpp b/editor/animation/animation_blend_tree_editor_plugin.cpp index 4df10d26ac9..01462e6fa92 100644 --- a/editor/animation/animation_blend_tree_editor_plugin.cpp +++ b/editor/animation/animation_blend_tree_editor_plugin.cpp @@ -127,6 +127,15 @@ void AnimationNodeBlendTreeEditor::update_graph() { visible_properties.clear(); + // Store selected nodes before clearing the graph. + List selected_nodes; + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to(graph->get_child(i)); + if (gn && gn->is_selected()) { + selected_nodes.push_back(gn->get_name()); + } + } + graph->set_scroll_offset(blend_tree->get_graph_offset() * EDSCALE); graph->clear_connections(); @@ -304,6 +313,17 @@ void AnimationNodeBlendTreeEditor::update_graph() { graph->set_minimap_opacity(graph_minimap_opacity); float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature"); graph->set_connection_lines_curvature(graph_lines_curvature); + + // Restore selected nodes after graph reconstruction. + for (const StringName &name : selected_nodes) { + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to(graph->get_child(i)); + if (gn && gn->get_name() == name) { + gn->set_selected(true); + break; + } + } + } } void AnimationNodeBlendTreeEditor::_file_opened(const String &p_file) { @@ -539,6 +559,9 @@ void AnimationNodeBlendTreeEditor::_delete_node_request(const String &p_which) { undo_redo->add_do_method(this, "update_graph"); undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); + + // Return selection to host BlendTree node. + EditorNode::get_singleton()->push_item(blend_tree.ptr(), "", true); } void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray &p_nodes) { @@ -597,6 +620,22 @@ void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) { EditorNode::get_singleton()->push_item(anode.ptr(), "", true); } +void AnimationNodeBlendTreeEditor::_node_deselected(Object *p_node) { + // Check if no nodes are selected, return selection to host BlendTree node. + bool any_selected = false; + for (int i = 0; i < graph->get_child_count(); i++) { + GraphNode *gn = Object::cast_to(graph->get_child(i)); + if (gn && gn->is_selected()) { + any_selected = true; + break; + } + } + + if (!any_selected) { + EditorNode::get_singleton()->push_item(blend_tree.ptr(), "", true); + } +} + void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) { Ref an = blend_tree->get_node(p_which); ERR_FAIL_COND(an.is_null()); @@ -1192,6 +1231,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { graph->connect("connection_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_request), CONNECT_DEFERRED); graph->connect("disconnection_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_disconnection_request), CONNECT_DEFERRED); graph->connect("node_selected", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_selected)); + graph->connect("node_deselected", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_deselected)); graph->connect("scroll_offset_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_scroll_changed)); graph->connect("delete_nodes_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_nodes_request)); graph->connect("popup_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_popup_request)); diff --git a/editor/animation/animation_blend_tree_editor_plugin.h b/editor/animation/animation_blend_tree_editor_plugin.h index e11f91280b5..a74e0eb50cd 100644 --- a/editor/animation/animation_blend_tree_editor_plugin.h +++ b/editor/animation/animation_blend_tree_editor_plugin.h @@ -111,6 +111,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void _scroll_changed(const Vector2 &p_scroll); void _node_selected(Object *p_node); + void _node_deselected(Object *p_node); void _open_in_editor(const String &p_which); void _anim_selected(int p_index, const Array &p_options, const String &p_node); void _delete_node_request(const String &p_which); diff --git a/editor/animation/animation_state_machine_editor.cpp b/editor/animation/animation_state_machine_editor.cpp index 6232150940b..cadbbace8e9 100644 --- a/editor/animation/animation_state_machine_editor.cpp +++ b/editor/animation/animation_state_machine_editor.cpp @@ -284,6 +284,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Refpush_item(state_machine.ptr(), "", true); + } + state_machine_draw->queue_redraw(); _update_mode(); } @@ -1648,6 +1653,10 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action connected_nodes.clear(); selected_nodes.clear(); + selected_node = StringName(); + + // Return selection to host StateMachine node. + EditorNode::get_singleton()->push_item(state_machine.ptr(), "", true); } if (selected_transition_to != StringName() && selected_transition_from != StringName() && state_machine->has_transition(selected_transition_from, selected_transition_to)) { @@ -1668,8 +1677,12 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action selected_transition_from = StringName(); selected_transition_to = StringName(); selected_transition_index = -1; + + // Return selection to host StateMachine node. + EditorNode::get_singleton()->push_item(state_machine.ptr(), "", true); } + _update_mode(); state_machine_draw->queue_redraw(); }