diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index 766566bf2b6b..c74d9fc3d457 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -1030,8 +1030,13 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) { } } -void SceneTreeEditor::_rename_node(Node *p_node, const String &p_name) { - TreeItem *item = _find(tree->get_root(), p_node->get_path()); +void SceneTreeEditor::rename_node(Node *p_node, const String &p_name, TreeItem *p_item) { + TreeItem *item; + if (p_item) { + item = p_item; // During batch rename the paths may change, so using _find() is unreliable. + } else { + item = _find(tree->get_root(), p_node->get_path()); + } ERR_FAIL_NULL(item); String new_name = p_name.validate_node_name(); @@ -1069,7 +1074,7 @@ void SceneTreeEditor::_rename_node(Node *p_node, const String &p_name) { // We previously made sure name is not the same as current name so that it won't complain about already used unique name when not changing name. if (p_node->is_unique_name_in_owner() && get_tree()->get_edited_scene_root()->get_node_or_null("%" + new_name)) { - String text = TTR("Another node already uses this unique name in the scene."); + String text = vformat(TTR("A node with the unique name %s already exists in this scene."), new_name); if (error->is_visible()) { if (!error->get_meta("same_unique_name", false)) { error->set_text(error->get_text() + "\n\n" + text); @@ -1091,7 +1096,7 @@ void SceneTreeEditor::_rename_node(Node *p_node, const String &p_name) { emit_signal(SNAME("node_renamed")); } else { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); - undo_redo->create_action("Rename Node", UndoRedo::MERGE_DISABLE, p_node); + undo_redo->create_action(TTR("Rename Node"), UndoRedo::MERGE_DISABLE, p_node); emit_signal(SNAME("node_prerename"), p_node, new_name); @@ -1108,17 +1113,37 @@ void SceneTreeEditor::_rename_node(Node *p_node, const String &p_name) { } } -void SceneTreeEditor::_renamed() { - TreeItem *which = tree->get_edited(); - +void SceneTreeEditor::_edited() { + TreeItem *which = tree->get_next_selected(nullptr); ERR_FAIL_NULL(which); - NodePath np = which->get_metadata(0); - Node *n = get_node(np); - ERR_FAIL_NULL(n); + TreeItem *edited = tree->get_edited(); + ERR_FAIL_NULL(edited); + + if (is_scene_tree_dock && tree->get_next_selected(which)) { + List nodes_to_rename; + for (TreeItem *item = which; item; item = tree->get_next_selected(item)) { + Node *n = get_node(item->get_metadata(0)); + ERR_FAIL_NULL(n); + nodes_to_rename.push_back(n); + } + ERR_FAIL_COND(nodes_to_rename.is_empty()); - String new_name = which->get_text(0); + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Rename Nodes"), UndoRedo::MERGE_DISABLE, nodes_to_rename.front()->get(), true); + + TreeItem *item = which; + String new_name = edited->get_text(0); + for (Node *n : nodes_to_rename) { + rename_node(n, new_name, item); + item = tree->get_next_selected(item); + } - _rename_node(n, new_name); + undo_redo->commit_action(); + } else { + Node *n = get_node(which->get_metadata(0)); + ERR_FAIL_NULL(n); + rename_node(n, which->get_text(0)); + } } Node *SceneTreeEditor::get_selected() { @@ -1491,7 +1516,6 @@ void SceneTreeEditor::set_connecting_signal(bool p_enable) { void SceneTreeEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_tree"), &SceneTreeEditor::_update_tree, DEFVAL(false)); // Still used by UndoRedo. - ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node); ClassDB::bind_method(D_METHOD("update_tree"), &SceneTreeEditor::update_tree); @@ -1543,7 +1567,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope } tree->connect("cell_selected", callable_mp(this, &SceneTreeEditor::_selected_changed)); - tree->connect("item_edited", callable_mp(this, &SceneTreeEditor::_renamed)); + tree->connect("item_edited", callable_mp(this, &SceneTreeEditor::_edited)); tree->connect("multi_selected", callable_mp(this, &SceneTreeEditor::_cell_multi_selected)); tree->connect("button_clicked", callable_mp(this, &SceneTreeEditor::_cell_button_pressed)); tree->connect("nothing_selected", callable_mp(this, &SceneTreeEditor::_deselect_items)); diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h index fe2396d43869..a869e867b82d 100644 --- a/editor/gui/scene_tree_editor.h +++ b/editor/gui/scene_tree_editor.h @@ -89,7 +89,6 @@ class SceneTreeEditor : public Control { void _notification(int p_what); void _selected_changed(); void _deselect_items(); - void _rename_node(Node *p_node, const String &p_name); void _cell_collapsed(Object *p_obj); @@ -101,7 +100,8 @@ class SceneTreeEditor : public Control { bool show_enabled_subscene = false; bool is_scene_tree_dock = false; - void _renamed(); + void _edited(); + void _renamed(TreeItem *p_item, TreeItem *p_batch_item, Node *p_node = nullptr); HashSet marked; bool marked_selectable = false; @@ -147,6 +147,8 @@ class SceneTreeEditor : public Control { // Public for use with callable_mp. void _update_tree(bool p_scroll_to_selected = false); + void rename_node(Node *p_node, const String &p_name, TreeItem *p_item = nullptr); + void set_filter(const String &p_filter); String get_filter() const; String get_filter_term_warning(); diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 6a43d60cc751..e63b90c0ac26 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -599,8 +599,7 @@ void RenameDialog::rename() { ERR_PRINT("Skipping missing node: " + to_rename[i].first.get_concatenated_subnames()); continue; } - - scene_tree_editor->call("_rename_node", n, new_name); + scene_tree_editor->rename_node(n, new_name); } undo_redo->commit_action(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 66b82ee64834..d60a4b3ba80a 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -3370,12 +3370,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } if (profile_allow_editing) { - bool add_separator = false; - - if (full_selection.size() == 1) { - add_separator = true; - menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Rename")), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); - } + menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Rename")), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); bool can_replace = true; for (Node *E : selection) { @@ -3386,14 +3381,11 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } if (can_replace) { - add_separator = true; menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Reload")), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE); } if (scene_tree->get_selected() != edited_scene) { - if (add_separator) { - menu->add_separator(); - } + menu->add_separator(); menu->add_icon_shortcut(get_editor_theme_icon(SNAME("MoveUp")), ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP); menu->add_icon_shortcut(get_editor_theme_icon(SNAME("MoveDown")), ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN); menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Duplicate")), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE);