summaryrefslogtreecommitdiffstats
path: root/editor/scene_tree_dock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/scene_tree_dock.cpp')
-rw-r--r--editor/scene_tree_dock.cpp190
1 files changed, 166 insertions, 24 deletions
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 6553a592d0..4d998118e2 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -29,20 +29,17 @@
/**************************************************************************/
#include "scene_tree_dock.h"
-#include "node_dock.h"
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/io/resource_saver.h"
#include "core/object/class_db.h"
-#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_feature_profile.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_quick_open.h"
-#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
@@ -50,12 +47,14 @@
#include "editor/gui/editor_file_dialog.h"
#include "editor/inspector_dock.h"
#include "editor/multi_node_edit.h"
+#include "editor/node_dock.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/reparent_dialog.h"
#include "editor/shader_create_dialog.h"
+#include "editor/themes/editor_scale.h"
#include "scene/animation/animation_tree.h"
#include "scene/gui/check_box.h"
#include "scene/main/window.h"
@@ -163,6 +162,20 @@ void SceneTreeDock::shortcut_input(const Ref<InputEvent> &p_event) {
accept_event();
}
+void SceneTreeDock::_scene_tree_gui_input(Ref<InputEvent> p_event) {
+ Ref<InputEventKey> key = p_event;
+
+ if (key.is_null() || !key->is_pressed() || key->is_echo()) {
+ return;
+ }
+
+ if (ED_IS_SHORTCUT("editor/open_search", p_event)) {
+ filter->grab_focus();
+ filter->select_all();
+ accept_event();
+ }
+}
+
void SceneTreeDock::instantiate(const String &p_file) {
Vector<String> scenes;
scenes.push_back(p_file);
@@ -713,7 +726,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
selection.sort_custom<Node::Comparator>();
- Node *add_below_node = selection.back()->get();
+ HashMap<const Node *, Node *> add_below_map;
+
+ for (List<Node *>::Element *E = selection.back(); E; E = E->prev()) {
+ Node *node = E->get();
+ if (!add_below_map.has(node->get_parent())) {
+ add_below_map.insert(node->get_parent(), node);
+ }
+ }
for (Node *node : selection) {
Node *parent = node->get_parent();
@@ -740,7 +760,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
dup->set_name(parent->validate_child_name(dup));
- undo_redo->add_do_method(add_below_node, "add_sibling", dup, true);
+ undo_redo->add_do_method(add_below_map[parent], "add_sibling", dup, true);
for (Node *F : owned) {
if (!duplimap.has(F)) {
@@ -759,7 +779,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
undo_redo->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name());
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(dup->get_name())));
- add_below_node = dup;
+ add_below_map[parent] = dup;
}
undo_redo->commit_action();
@@ -1236,7 +1256,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (cant_be_set_unique_names.size()) {
String popup_text = TTR("Unique names already used by another node in the scene:");
popup_text += "\n";
- for (StringName name : cant_be_set_unique_names) {
+ for (const StringName &name : cant_be_set_unique_names) {
popup_text += "\n" + String(name);
}
accept->set_text(popup_text);
@@ -1386,7 +1406,7 @@ void SceneTreeDock::_notification(int p_what) {
node_shortcuts_toggle->set_flat(true);
node_shortcuts_toggle->set_icon(get_editor_theme_icon(SNAME("Favorites")));
node_shortcuts_toggle->set_toggle_mode(true);
- node_shortcuts_toggle->set_tooltip_text(TTR("Switch to Favorite Nodes"));
+ node_shortcuts_toggle->set_tooltip_text(TTR("Toggle the display of favorite nodes."));
node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT);
node_shortcuts_toggle->connect("pressed", callable_mp(this, &SceneTreeDock::_update_create_root_dialog));
@@ -1558,7 +1578,9 @@ void SceneTreeDock::_load_request(const String &p_path) {
}
void SceneTreeDock::_script_open_request(const Ref<Script> &p_script) {
- EditorNode::get_singleton()->edit_resource(p_script);
+ if (ScriptEditor::get_singleton()->edit(p_script, true)) {
+ EditorNode::get_singleton()->editor_select(EditorNode::EDITOR_SCRIPT);
+ }
}
void SceneTreeDock::_push_item(Object *p_object) {
@@ -2311,20 +2333,123 @@ void SceneTreeDock::_toggle_placeholder_from_selection() {
}
}
-void SceneTreeDock::_toggle_editable_children(Node *p_node) {
- if (p_node) {
- bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
- EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(p_node, editable);
- if (editable) {
- p_node->set_scene_instance_load_placeholder(false);
+void SceneTreeDock::_reparent_nodes_to_root(Node *p_root, const Array &p_nodes, Node *p_owner) {
+ List<Node *> nodes;
+ for (int i = 0; i < p_nodes.size(); i++) {
+ Node *node = Object::cast_to<Node>(p_nodes[i]);
+ ERR_FAIL_NULL(node);
+ nodes.push_back(node);
+ }
+
+ for (Node *node : nodes) {
+ node->set_owner(p_owner);
+ List<Node *> owned;
+ node->get_owned_by(p_owner, &owned);
+ String original_name = node->get_name();
+ node->reparent(p_root);
+ node->set_name(original_name);
+
+ for (Node *F : owned) {
+ F->set_owner(p_owner);
}
+ }
+}
+
+void SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name(Node *p_root, const Array &p_nodes, const Array &p_paths, const Array &p_transforms, const Array &p_names, Node *p_owner) {
+ ERR_FAIL_COND(p_nodes.size() != p_paths.size());
+ ERR_FAIL_COND(p_nodes.size() != p_transforms.size());
+ ERR_FAIL_COND(p_nodes.size() != p_names.size());
+
+ for (int i = 0; i < p_nodes.size(); i++) {
+ Node *node = Object::cast_to<Node>(p_nodes[i]);
+ ERR_FAIL_NULL(node);
+ const NodePath &np = p_paths[i];
+ Node *parent_node = p_root->get_node_or_null(np);
+ ERR_FAIL_NULL(parent_node);
- Node3DEditor::get_singleton()->update_all_gizmos(p_node);
+ List<Node *> owned;
+ node->get_owned_by(p_owner, &owned);
+ node->reparent(parent_node);
+ node->set_name(p_names[i]);
+ Node3D *node_3d = Object::cast_to<Node3D>(node);
+ if (node_3d) {
+ node_3d->set_transform(p_transforms[i]);
+ } else {
+ Node2D *node_2d = Object::cast_to<Node2D>(node);
+ if (node_2d) {
+ node_2d->set_transform(p_transforms[i]);
+ }
+ }
- scene_tree->update_tree();
+ for (Node *F : owned) {
+ F->set_owner(p_owner);
+ }
}
}
+void SceneTreeDock::_toggle_editable_children(Node *p_node) {
+ if (!p_node) {
+ return;
+ }
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+
+ undo_redo->create_action(TTR("Toggle Editable Children"));
+
+ bool editable = !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node);
+
+ undo_redo->add_undo_method(EditorNode::get_singleton()->get_edited_scene(), "set_editable_instance", p_node, !editable);
+ undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "set_editable_instance", p_node, editable);
+
+ if (editable) {
+ bool original_scene_instance_load_placeholder = p_node->get_scene_instance_load_placeholder();
+
+ undo_redo->add_undo_method(p_node, "set_scene_instance_load_placeholder", original_scene_instance_load_placeholder);
+ undo_redo->add_do_method(p_node, "set_scene_instance_load_placeholder", false);
+ } else {
+ List<Node *> owned;
+ p_node->get_owned_by(edited_scene, &owned);
+
+ // Get the original paths, transforms, and names for undo.
+ Array owned_nodes_array;
+ Array paths_array;
+ Array transform_array;
+ Array name_array;
+
+ for (Node *owned_node : owned) {
+ if (owned_node != p_node && owned_node != edited_scene && owned_node->get_owner() == edited_scene && owned_node->get_parent()->get_owner() != edited_scene) {
+ owned_nodes_array.push_back(owned_node);
+ paths_array.push_back(p_node->get_path_to(owned_node->get_parent()));
+ name_array.push_back(owned_node->get_name());
+ Node3D *node_3d = Object::cast_to<Node3D>(owned_node);
+ if (node_3d) {
+ transform_array.push_back(node_3d->get_transform());
+ } else {
+ Node2D *node_2d = Object::cast_to<Node2D>(owned_node);
+ if (node_2d) {
+ transform_array.push_back(node_2d->get_transform());
+ } else {
+ transform_array.push_back(Variant());
+ }
+ }
+ }
+ }
+
+ if (!owned_nodes_array.is_empty()) {
+ undo_redo->add_undo_method(this, "_reparent_nodes_to_paths_with_transform_and_name", p_node, owned_nodes_array, paths_array, transform_array, name_array, edited_scene);
+ undo_redo->add_do_method(this, "_reparent_nodes_to_root", p_node, owned_nodes_array, edited_scene);
+ }
+ }
+
+ undo_redo->add_undo_method(Node3DEditor::get_singleton(), "update_all_gizmos", p_node);
+ undo_redo->add_do_method(Node3DEditor::get_singleton(), "update_all_gizmos", p_node);
+
+ undo_redo->add_undo_method(scene_tree, "update_tree");
+ undo_redo->add_do_method(scene_tree, "update_tree");
+
+ undo_redo->commit_action();
+}
+
void SceneTreeDock::_delete_confirm(bool p_cut) {
List<Node *> remove_list = editor_selection->get_selected_node_list();
@@ -2802,12 +2927,17 @@ void SceneTreeDock::_new_scene_from(String p_file) {
Node *base = selection.front()->get();
HashMap<const Node *, Node *> duplimap;
+ HashMap<const Node *, Node *> inverse_duplimap;
Node *copy = base->duplicate_from_editor(duplimap);
+ for (const KeyValue<const Node *, Node *> &item : duplimap) {
+ inverse_duplimap[item.value] = const_cast<Node *>(item.key);
+ }
+
if (copy) {
// Handle Unique Nodes.
for (int i = 0; i < copy->get_child_count(false); i++) {
- _set_node_owner_recursive(copy->get_child(i, false), copy);
+ _set_node_owner_recursive(copy->get_child(i, false), copy, inverse_duplimap);
}
// Root node cannot ever be unique name in its own Scene!
copy->set_unique_name_in_owner(false);
@@ -2841,13 +2971,18 @@ void SceneTreeDock::_new_scene_from(String p_file) {
}
}
-void SceneTreeDock::_set_node_owner_recursive(Node *p_node, Node *p_owner) {
- if (!p_node->get_owner()) {
- p_node->set_owner(p_owner);
+void SceneTreeDock::_set_node_owner_recursive(Node *p_node, Node *p_owner, const HashMap<const Node *, Node *> &p_inverse_duplimap) {
+ HashMap<const Node *, Node *>::ConstIterator E = p_inverse_duplimap.find(p_node);
+
+ if (E) {
+ const Node *original = E->value;
+ if (original->get_owner()) {
+ p_node->set_owner(p_owner);
+ }
}
for (int i = 0; i < p_node->get_child_count(false); i++) {
- _set_node_owner_recursive(p_node->get_child(i, false), p_owner);
+ _set_node_owner_recursive(p_node->get_child(i, false), p_owner, p_inverse_duplimap);
}
}
@@ -2932,7 +3067,7 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_
_normalize_drop(node, to_pos, p_type);
_perform_instantiate_scenes(p_files, node, to_pos);
} else {
- String res_path = p_files[0];
+ const String &res_path = p_files[0];
StringName res_type = EditorFileSystem::get_singleton()->get_file_type(res_path);
List<String> valid_properties;
@@ -3048,6 +3183,9 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) {
_normalize_drop(to_node, to_pos, p_type);
_do_reparent(to_node, to_pos, nodes, !Input::get_singleton()->is_key_pressed(Key::SHIFT));
+ for (Node *E : nodes) {
+ editor_selection->add_node(E);
+ }
}
void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
@@ -3874,6 +4012,7 @@ void SceneTreeDock::_list_all_subresources(PopupMenu *p_menu) {
}
p_menu->add_item(display_text);
+ p_menu->set_item_tooltip(-1, pair.first->get_path());
p_menu->set_item_metadata(-1, pair.first->get_instance_id());
}
}
@@ -3935,6 +4074,8 @@ void SceneTreeDock::_edit_subresource(int p_idx, const PopupMenu *p_from_menu) {
void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners);
+ ClassDB::bind_method(D_METHOD("_reparent_nodes_to_root"), &SceneTreeDock::_reparent_nodes_to_root);
+ ClassDB::bind_method(D_METHOD("_reparent_nodes_to_paths_with_transform_and_name"), &SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name);
ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button);
@@ -3951,7 +4092,7 @@ SceneTreeDock *SceneTreeDock::singleton = nullptr;
void SceneTreeDock::_update_configuration_warning() {
if (singleton) {
- MessageQueue::get_singleton()->push_callable(callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning));
+ callable_mp(singleton->scene_tree, &SceneTreeEditor::update_warning).call_deferred();
}
}
@@ -4099,6 +4240,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
scene_tree->connect("script_dropped", callable_mp(this, &SceneTreeDock::_script_dropped));
scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin));
+ scene_tree->get_scene_tree()->connect("gui_input", callable_mp(this, &SceneTreeDock::_scene_tree_gui_input));
scene_tree->get_scene_tree()->connect("item_icon_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node));
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));