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.cpp291
1 files changed, 196 insertions, 95 deletions
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index d1e2ba0fe0..d882c4652d 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "scene_tree_dock.h"
+#include "node_dock.h"
#include "core/config/project_settings.h"
#include "core/input/input.h"
@@ -54,6 +55,7 @@
#include "editor/plugins/script_editor_plugin.h"
#include "editor/reparent_dialog.h"
#include "editor/shader_create_dialog.h"
+#include "scene/animation/animation_tree.h"
#include "scene/gui/check_box.h"
#include "scene/main/window.h"
#include "scene/property_utils.h"
@@ -377,6 +379,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
if (editor_selection->get_selected_node_list().size() > 1) {
+ if (!_validate_no_foreign()) {
+ break;
+ }
rename_dialog->popup_centered();
}
} break;
@@ -387,6 +392,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
Tree *tree = scene_tree->get_scene_tree();
if (tree->is_anything_selected()) {
+ if (!_validate_no_foreign()) {
+ break;
+ }
tree->grab_focus();
tree->edit_selected();
}
@@ -493,16 +501,25 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
// Preserve ownership relations ready for pasting.
List<Node *> owned;
- node->get_owned_by(node->get_owner() ? node->get_owner() : node, &owned);
+ Node *owner = node;
+ while (owner) {
+ List<Node *> cur_owned;
+ node->get_owned_by(owner, &cur_owned);
+ owner = owner->get_owner();
+ for (Node *F : cur_owned) {
+ owned.push_back(F);
+ }
+ }
for (Node *F : owned) {
if (!duplimap.has(F) || F == node) {
continue;
}
Node *d = duplimap[F];
- // Only use this as a marker that ownership needs to be assigned when pasting.
- // The actual owner doesn't matter.
- d->set_owner(dup);
+ // Only use nullptr as a marker that ownership may need to be assigned when pasting.
+ // The ownership is subsequently tracked in the node_clipboard_edited_scene_owned list.
+ d->set_owner(nullptr);
+ node_clipboard_edited_scene_owned.insert(d);
}
node_clipboard.push_back(dup);
@@ -680,10 +697,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- if (!_validate_no_foreign()) {
- break;
- }
-
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() == 0) {
break;
@@ -703,7 +716,15 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *parent = node->get_parent();
List<Node *> owned;
- node->get_owned_by(node->get_owner(), &owned);
+ Node *owner = node;
+ while (owner) {
+ List<Node *> cur_owned;
+ node->get_owned_by(owner, &cur_owned);
+ owner = owner->get_owner();
+ for (Node *F : cur_owned) {
+ owned.push_back(F);
+ }
+ }
HashMap<const Node *, Node *> duplimap;
Node *dup = node->duplicate_from_editor(duplimap);
@@ -723,9 +744,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
continue;
}
Node *d = duplimap[F];
- undo_redo->add_do_method(d, "set_owner", node->get_owner());
+ undo_redo->add_do_method(d, "set_owner", edited_scene);
}
undo_redo->add_do_method(editor_selection, "add_node", dup);
+ undo_redo->add_do_method(dup, "set_owner", edited_scene);
undo_redo->add_undo_method(parent, "remove_child", dup);
undo_redo->add_do_reference(dup);
@@ -1040,7 +1062,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
// Fire confirmation dialog when children are editable.
if (editable && !placeholder) {
- placeholder_editable_instance_remove_dialog->set_text(TTR("Enabling \"Load As Placeholder\" will disable \"Editable Children\" and cause all properties of the node to be reverted to their default."));
+ placeholder_editable_instance_remove_dialog->set_text(TTR("Enabling \"Load as Placeholder\" will disable \"Editable Children\" and cause all properties of the node to be reverted to their default."));
placeholder_editable_instance_remove_dialog->popup_centered();
break;
}
@@ -1081,6 +1103,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
undo_redo->add_do_method(node, "set_scene_file_path", "");
undo_redo->add_undo_method(node, "set_scene_file_path", node->get_scene_file_path());
_node_replace_owner(node, node, root);
+ _node_strip_signal_inheritance(node);
+ NodeDock::get_singleton()->set_node(node); // Refresh.
undo_redo->add_do_method(scene_tree, "update_tree");
undo_redo->add_undo_method(scene_tree, "update_tree");
undo_redo->commit_action();
@@ -1144,9 +1168,25 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
}
- bool enabling = !first_selected->get()->is_unique_name_in_owner();
List<Node *> full_selection = editor_selection->get_full_selected_node_list();
+
+ // Check if all the nodes for this operation are invalid, and if they are, pop up a dialog and end here.
+ bool all_nodes_owner_invalid = true;
+ for (Node *node : full_selection) {
+ if (node->get_owner() == get_tree()->get_edited_scene_root()) {
+ all_nodes_owner_invalid = false;
+ break;
+ }
+ }
+ if (all_nodes_owner_invalid) {
+ accept->set_text(TTR("Can't toggle unique name for nodes in subscene!"));
+ accept->popup_centered();
+ return;
+ }
+
+ bool enabling = !first_selected->get()->is_unique_name_in_owner();
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (enabling) {
@@ -1158,6 +1198,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (node->is_unique_name_in_owner()) {
continue;
}
+ if (node->get_owner() != get_tree()->get_edited_scene_root()) {
+ continue;
+ }
+
StringName name = node->get_name();
if (new_unique_names.find(name) != -1 || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) {
cant_be_set_unique_names.push_back(name);
@@ -1191,6 +1235,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!node->is_unique_name_in_owner()) {
continue;
}
+ if (node->get_owner() != get_tree()->get_edited_scene_root()) {
+ continue;
+ }
undo_redo->add_do_method(node, "set_unique_name_in_owner", false);
undo_redo->add_undo_method(node, "set_unique_name_in_owner", true);
}
@@ -1479,6 +1526,19 @@ void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root
}
}
+void SceneTreeDock::_node_strip_signal_inheritance(Node *p_node) {
+ List<Object::Connection> conns;
+ p_node->get_all_signal_connections(&conns);
+
+ for (Object::Connection conn : conns) {
+ conn.signal.disconnect(conn.callable);
+ conn.signal.connect(conn.callable, conn.flags & ~CONNECT_INHERITED);
+ }
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ _node_strip_signal_inheritance(p_node->get_child(i));
+ }
+}
+
void SceneTreeDock::_load_request(const String &p_path) {
EditorNode::get_singleton()->open_request(p_path);
_local_tree_selected();
@@ -1550,6 +1610,14 @@ void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path, Vector<Stri
}
bool SceneTreeDock::_has_tracks_to_delete(Node *p_node, List<Node *> &p_to_delete) const {
+ // Skip if this node will be deleted.
+ for (const Node *F : p_to_delete) {
+ if (F == p_node || F->is_ancestor_of(p_node)) {
+ return false;
+ }
+ }
+
+ // This is an AnimationPlayer that survives the deletion.
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
if (ap) {
Node *root = ap->get_node(ap->get_root_node());
@@ -1578,11 +1646,13 @@ bool SceneTreeDock::_has_tracks_to_delete(Node *p_node, List<Node *> &p_to_delet
}
}
+ // Recursively check child nodes.
for (int i = 0; i < p_node->get_child_count(); i++) {
if (_has_tracks_to_delete(p_node->get_child(i), p_to_delete)) {
return true;
}
}
+
return false;
}
@@ -1698,6 +1768,11 @@ bool SceneTreeDock::_check_node_path_recursive(Node *p_root_node, Variant &r_var
break;
}
+ if (Object::cast_to<Animation>(resource)) {
+ // Animation resources are handled by animation editor.
+ break;
+ }
+
List<PropertyInfo> properties;
resource->get_property_list(&properties);
@@ -1745,95 +1820,93 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
return;
}
- // Renaming node paths used in node properties.
- List<PropertyInfo> properties;
- p_base->get_property_list(&properties);
-
- for (const PropertyInfo &E : properties) {
- if (!(E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
- continue;
- }
- String propertyname = E.name;
- Variant old_variant = p_base->get(propertyname);
- Variant updated_variant = old_variant;
- if (_check_node_path_recursive(p_base, updated_variant, p_renames)) {
- EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->add_do_property(p_base, propertyname, updated_variant);
- undo_redo->add_undo_property(p_base, propertyname, old_variant);
- p_base->set(propertyname, updated_variant);
- }
- }
-
bool autorename_animation_tracks = bool(EDITOR_GET("editors/animation/autorename_animation_tracks"));
- if (autorename_animation_tracks && Object::cast_to<AnimationPlayer>(p_base)) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_base);
- List<StringName> anims;
- ap->get_animation_list(&anims);
- Node *root = ap->get_node(ap->get_root_node());
+ AnimationMixer *mixer = Object::cast_to<AnimationMixer>(p_base);
+ if (autorename_animation_tracks && mixer) {
+ // Don't rename if we're an AnimationTree pointing to an AnimationPlayer
+ bool points_to_other_animation_player = false;
+ AnimationTree *at = Object::cast_to<AnimationTree>(mixer);
+ if (at) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(at->get_node_or_null(at->get_animation_player()));
+ if (ap) {
+ points_to_other_animation_player = true;
+ }
+ }
- if (root) {
- HashMap<Node *, NodePath>::Iterator found_root_path = p_renames->find(root);
- NodePath new_root_path = found_root_path ? found_root_path->value : root->get_path();
- if (!new_root_path.is_empty()) { // No renaming if root node is deleted.
- for (const StringName &E : anims) {
- Ref<Animation> anim = ap->get_animation(E);
- if (!r_rem_anims->has(anim)) {
- r_rem_anims->insert(anim, HashSet<int>());
- HashSet<int> &ran = r_rem_anims->find(anim)->value;
- for (int i = 0; i < anim->get_track_count(); i++) {
- ran.insert(i);
+ if (!points_to_other_animation_player) {
+ List<StringName> anims;
+ mixer->get_animation_list(&anims);
+ Node *root = mixer->get_node(mixer->get_root_node());
+
+ if (root) {
+ HashMap<Node *, NodePath>::Iterator found_root_path = p_renames->find(root);
+ NodePath new_root_path = found_root_path ? found_root_path->value : root->get_path();
+ if (!new_root_path.is_empty()) { // No renaming if root node is deleted.
+ for (const StringName &E : anims) {
+ Ref<Animation> anim = mixer->get_animation(E);
+ if (!r_rem_anims->has(anim)) {
+ r_rem_anims->insert(anim, HashSet<int>());
+ HashSet<int> &ran = r_rem_anims->find(anim)->value;
+ for (int i = 0; i < anim->get_track_count(); i++) {
+ ran.insert(i);
+ }
}
- }
- HashSet<int> &ran = r_rem_anims->find(anim)->value;
-
- if (anim.is_null()) {
- continue;
- }
-
- int tracks_removed = 0;
+ HashSet<int> &ran = r_rem_anims->find(anim)->value;
- for (int i = 0; i < anim->get_track_count(); i++) {
- NodePath track_np = anim->track_get_path(i);
- Node *n = root->get_node_or_null(track_np);
- if (!n) {
+ if (anim.is_null() || EditorNode::get_singleton()->is_resource_read_only(anim)) {
continue;
}
- if (!ran.has(i)) {
- continue; //channel was removed
- }
+ int tracks_removed = 0;
- HashMap<Node *, NodePath>::Iterator found_path = p_renames->find(n);
- EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- if (found_path) {
- if (found_path->value.is_empty()) {
- //will be erased
-
- int idx = i - tracks_removed;
- tracks_removed++;
-
- undo_redo->add_do_method(anim.ptr(), "remove_track", idx);
- undo_redo->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
- undo_redo->add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
- undo_redo->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
- for (int j = 0; j < anim->track_get_key_count(i); j++) {
- undo_redo->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
- }
+ for (int i = 0; i < anim->get_track_count(); i++) {
+ if (anim->track_is_imported(i)) {
+ continue;
+ }
- ran.erase(i); //byebye channel
+ NodePath track_np = anim->track_get_path(i);
- } else {
- //will be renamed
- NodePath rel_path = new_root_path.rel_path_to(found_path->value);
+ Node *n = root->get_node_or_null(track_np);
+ if (!n) {
+ continue;
+ }
+
+ if (!ran.has(i)) {
+ continue; //channel was removed
+ }
- NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false);
- if (new_path == track_np) {
- continue; //bleh
+ HashMap<Node *, NodePath>::Iterator found_path = p_renames->find(n);
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ if (found_path) {
+ if (found_path->value.is_empty()) {
+ //will be erased
+
+ int idx = i - tracks_removed;
+ tracks_removed++;
+
+ undo_redo->add_do_method(anim.ptr(), "remove_track", idx);
+ undo_redo->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
+ undo_redo->add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
+ undo_redo->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
+ for (int j = 0; j < anim->track_get_key_count(i); j++) {
+ undo_redo->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
+ }
+
+ ran.erase(i); //byebye channel
+
+ } else {
+ //will be renamed
+ NodePath rel_path = new_root_path.rel_path_to(found_path->value);
+
+ NodePath new_path = NodePath(rel_path.get_names(), track_np.get_subnames(), false);
+ if (new_path == track_np) {
+ continue; //bleh
+ }
+ undo_redo->add_do_method(anim.ptr(), "track_set_path", i, new_path);
+ undo_redo->add_undo_method(anim.ptr(), "track_set_path", i, track_np);
}
- undo_redo->add_do_method(anim.ptr(), "track_set_path", i, new_path);
- undo_redo->add_undo_method(anim.ptr(), "track_set_path", i, track_np);
}
}
}
@@ -1842,6 +1915,25 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
}
}
+ // Renaming node paths used in node properties.
+ List<PropertyInfo> properties;
+ p_base->get_property_list(&properties);
+
+ for (const PropertyInfo &E : properties) {
+ if (!(E.usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) {
+ continue;
+ }
+ String propertyname = E.name;
+ Variant old_variant = p_base->get(propertyname);
+ Variant updated_variant = old_variant;
+ if (_check_node_path_recursive(p_base, updated_variant, p_renames)) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->add_do_property(p_base, propertyname, updated_variant);
+ undo_redo->add_undo_property(p_base, propertyname, old_variant);
+ p_base->set(propertyname, updated_variant);
+ }
+ }
+
for (int i = 0; i < p_base->get_child_count(); i++) {
perform_node_renames(p_base->get_child(i), p_renames, r_rem_anims);
}
@@ -2136,8 +2228,13 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
}
undo_redo->commit_action();
+ // Avoid changing the currently edited object.
+ Object *edited_object = InspectorDock::get_inspector_singleton()->get_edited_object();
+
_push_item(p_script.ptr());
_update_script_button();
+
+ InspectorDock::get_inspector_singleton()->edit(edited_object);
}
void SceneTreeDock::_shader_created(Ref<Shader> p_shader) {
@@ -2959,7 +3056,7 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj);
if (menu->get_item_count() == 0) {
- menu->add_submenu_item(TTR("Sub-Resources"), "Sub-Resources");
+ menu->add_submenu_item(TTR("Sub-Resources"), "SubResources");
}
menu_subresources->add_icon_item(icon, E.name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size());
menu_subresources->set_item_indent(-1, p_depth);
@@ -3149,13 +3246,13 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
bool placeholder = selection[0]->get_scene_instance_load_placeholder();
if (profile_allow_editing) {
menu->add_check_item(TTR("Editable Children"), TOOL_SCENE_EDITABLE_CHILDREN);
- menu->add_check_item(TTR("Load As Placeholder"), TOOL_SCENE_USE_PLACEHOLDER);
+ menu->add_check_item(TTR("Load as Placeholder"), TOOL_SCENE_USE_PLACEHOLDER);
menu->add_item(TTR("Make Local"), TOOL_SCENE_MAKE_LOCAL);
}
menu->add_icon_item(get_editor_theme_icon(SNAME("Load")), TTR("Open in Editor"), TOOL_SCENE_OPEN);
if (profile_allow_editing) {
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Editable Children")), editable);
- menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load As Placeholder")), placeholder);
+ menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load as Placeholder")), placeholder);
}
}
}
@@ -3493,14 +3590,17 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
for (KeyValue<const Node *, Node *> &E2 : duplimap) {
Node *d = E2.value;
- // When copying, all nodes that should have an owner assigned here were given node as an owner.
- if (d != dup && E2.key->get_owner() == node) {
- ur->add_do_method(d, "set_owner", owner);
+ // When copying, all nodes that should have an owner assigned here were given nullptr as an owner
+ // and added to the node_clipboard_edited_scene_owned list.
+ if (d != dup && E2.key->get_owner() == nullptr) {
+ if (node_clipboard_edited_scene_owned.find(const_cast<Node *>(E2.key))) {
+ ur->add_do_method(d, "set_owner", edited_scene);
+ }
}
}
if (dup != owner) {
- ur->add_do_method(dup, "set_owner", owner);
+ ur->add_do_method(dup, "set_owner", edited_scene);
}
ur->add_do_method(editor_selection, "add_node", dup);
@@ -3647,6 +3747,7 @@ void SceneTreeDock::_clear_clipboard() {
memdelete(E);
}
node_clipboard.clear();
+ node_clipboard_edited_scene_owned.clear();
clipboard_resource_remap.clear();
}
@@ -4041,7 +4142,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
menu_subresources = memnew(PopupMenu);
- menu_subresources->set_name("Sub-Resources");
+ menu_subresources->set_name("SubResources");
menu_subresources->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(false));
menu->add_child(menu_subresources);