summaryrefslogtreecommitdiff
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.cpp247
1 files changed, 155 insertions, 92 deletions
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 8d4e7b444b..3dbbb30b0e 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -361,8 +361,12 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
tree->edit_selected();
}
} break;
- case TOOL_NEW:
- case TOOL_REPARENT_TO_NEW_NODE: {
+ case TOOL_REPARENT_TO_NEW_NODE:
+ if (!_validate_no_foreign()) {
+ break;
+ }
+ [[fallthrough]];
+ case TOOL_NEW: {
if (!profile_allow_editing) {
break;
}
@@ -441,8 +445,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
+ bool was_empty = false;
if (!node_clipboard.is_empty()) {
_clear_clipboard();
+ } else {
+ was_empty = true;
}
clipboard_source_scene = editor->get_edited_scene()->get_scene_file_path();
@@ -460,81 +467,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (p_tool == TOOL_CUT) {
_delete_confirm(true);
}
- } break;
- case TOOL_PASTE: {
- if (node_clipboard.is_empty() || !edited_scene) {
- break;
- }
- bool has_cycle = false;
- if (!edited_scene->get_scene_file_path().is_empty()) {
- for (Node *E : node_clipboard) {
- if (edited_scene->get_scene_file_path() == E->get_scene_file_path()) {
- has_cycle = true;
- break;
- }
- }
- }
-
- if (has_cycle) {
- current_option = -1;
- accept->set_text(TTR("Can't paste root node into the same scene."));
- accept->popup_centered();
- break;
- }
-
- Node *paste_parent = edited_scene;
- List<Node *> selection = editor_selection->get_selected_node_list();
- if (selection.size() > 0) {
- paste_parent = selection.back()->get();
- }
-
- Node *owner = paste_parent->get_owner();
- if (!owner) {
- owner = paste_parent;
- }
-
- editor_data->get_undo_redo().create_action(TTR("Paste Node(s)"));
- editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
-
- Map<RES, RES> resource_remap;
- String target_scene = editor->get_edited_scene()->get_scene_file_path();
- if (target_scene != clipboard_source_scene) {
- if (!clipboard_resource_remap.has(target_scene)) {
- Map<RES, RES> remap;
- for (Node *E : node_clipboard) {
- _create_remap_for_node(E, remap);
- }
- clipboard_resource_remap[target_scene] = remap;
- }
- resource_remap = clipboard_resource_remap[target_scene];
+ if (was_empty) {
+ _update_create_root_dialog();
}
-
- for (Node *node : node_clipboard) {
- Map<const Node *, Node *> duplimap;
-
- Node *dup = node->duplicate_from_editor(duplimap, resource_remap);
-
- ERR_CONTINUE(!dup);
-
- editor_data->get_undo_redo().add_do_method(paste_parent, "add_child", dup, true);
-
- for (KeyValue<const Node *, Node *> &E2 : duplimap) {
- Node *d = E2.value;
- editor_data->get_undo_redo().add_do_method(d, "set_owner", owner);
- }
-
- editor_data->get_undo_redo().add_do_method(dup, "set_owner", owner);
- editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", dup);
- editor_data->get_undo_redo().add_undo_method(paste_parent, "remove_child", dup);
- editor_data->get_undo_redo().add_do_reference(dup);
-
- if (node_clipboard.size() == 1) {
- editor_data->get_undo_redo().add_do_method(editor, "push_item", dup);
- }
- }
-
- editor_data->get_undo_redo().commit_action();
+ } break;
+ case TOOL_PASTE: {
+ paste_nodes();
} break;
case TOOL_REPLACE: {
if (!profile_allow_editing) {
@@ -726,7 +665,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
dup->set_name(parent->validate_child_name(dup));
- editor_data->get_undo_redo().add_do_method(add_below_node, "add_sibling", dup);
+ editor_data->get_undo_redo().add_do_method(add_below_node, "add_sibling", dup, true);
for (Node *F : owned) {
if (!duplimap.has(F)) {
@@ -942,6 +881,18 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
+ if (tocopy->get_owner() != scene) {
+ accept->set_text(TTR("Can't save a branch which is a child of an already instantiated scene.\nTo save this branch into its own scene, open the original scene, right click on this branch, and select \"Save Branch as Scene\"."));
+ accept->popup_centered();
+ break;
+ }
+
+ if (scene->get_scene_inherited_state().is_valid() && scene->get_scene_inherited_state()->find_node_by_path(scene->get_path_to(tocopy)) >= 0) {
+ accept->set_text(TTR("Can't save a branch which is part of an inherited scene.\nTo save this branch into its own scene, open the original scene, right click on this branch, and select \"Save Branch as Scene\"."));
+ accept->popup_centered();
+ break;
+ }
+
new_scene_from_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
List<String> extensions;
@@ -1290,6 +1241,12 @@ void SceneTreeDock::_notification(int p_what) {
button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_custom->connect("pressed", callable_bind(callable_mp(this, &SceneTreeDock::_tool_selected), TOOL_NEW, false));
+ button_clipboard = memnew(Button);
+ node_shortcuts->add_child(button_clipboard);
+ button_clipboard->set_text(TTR("Paste From Clipboard"));
+ button_clipboard->set_icon(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")));
+ button_clipboard->connect("pressed", callable_bind(callable_mp(this, &SceneTreeDock::_tool_selected), TOOL_PASTE, false));
+
node_shortcuts->add_spacer();
create_root_dialog->add_child(node_shortcuts);
_update_create_root_dialog();
@@ -1314,6 +1271,7 @@ void SceneTreeDock::_notification(int p_what) {
button_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
button_ui->set_icon(get_theme_icon(SNAME("Control"), SNAME("EditorIcons")));
button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ button_clipboard->set_icon(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")));
filter->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
filter->set_clear_button_enabled(true);
@@ -2609,6 +2567,10 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
}
void SceneTreeDock::_nodes_dragged(Array p_nodes, NodePath p_to, int p_type) {
+ if (!_validate_no_foreign()) {
+ return;
+ }
+
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.is_empty()) {
@@ -2709,6 +2671,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_icon_shortcut(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE);
}
+ menu->add_icon_shortcut(get_theme_icon(SNAME("Collapse"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE);
menu->add_separator();
existing_script = selected->get_script();
@@ -2719,10 +2682,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
}
if (profile_allow_editing) {
- menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/cut_node"), TOOL_CUT);
- menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
+ menu->add_icon_shortcut(get_theme_icon(SNAME("ActionCut"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/cut_node"), TOOL_CUT);
+ menu->add_icon_shortcut(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
if (selection.size() == 1 && !node_clipboard.is_empty()) {
- menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/paste_node"), TOOL_PASTE);
+ menu->add_icon_shortcut(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/paste_node"), TOOL_PASTE);
}
menu->add_separator();
}
@@ -2846,16 +2809,9 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->popup();
}
-void SceneTreeDock::_open_tree_menu() {
- menu->clear();
-
- menu->add_icon_shortcut(get_theme_icon(SNAME("Collapse"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE);
- menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND);
- menu->set_item_checked(menu->get_item_idx_from_text(TTR("Auto Expand to Selected")), EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected"));
-
- menu->reset_size();
- menu->set_position(get_screen_position() + get_local_mouse_position());
- menu->popup();
+void SceneTreeDock::_update_tree_menu() {
+ PopupMenu *tree_menu = button_tree_menu->get_popup();
+ tree_menu->set_item_checked(tree_menu->get_item_idx_from_text(TTR("Auto Expand to Selected")), EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected"));
}
void SceneTreeDock::_filter_changed(const String &p_filter) {
@@ -3002,6 +2958,108 @@ void SceneTreeDock::open_instance_child_dialog() {
_tool_selected(TOOL_INSTANTIATE, true);
}
+List<Node *> SceneTreeDock::paste_nodes() {
+ List<Node *> pasted_nodes;
+
+ if (node_clipboard.is_empty()) {
+ return pasted_nodes;
+ }
+
+ bool has_cycle = false;
+ if (edited_scene && !edited_scene->get_scene_file_path().is_empty()) {
+ for (Node *E : node_clipboard) {
+ if (edited_scene->get_scene_file_path() == E->get_scene_file_path()) {
+ has_cycle = true;
+ break;
+ }
+ }
+ }
+
+ if (has_cycle) {
+ current_option = -1;
+ accept->set_text(TTR("Can't paste root node into the same scene."));
+ accept->popup_centered();
+ return pasted_nodes;
+ }
+
+ Node *paste_parent = edited_scene;
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ if (selection.size() > 0) {
+ paste_parent = selection.back()->get();
+ }
+
+ Node *owner = nullptr;
+ if (paste_parent) {
+ owner = paste_parent->get_owner();
+ }
+ if (!owner) {
+ owner = paste_parent;
+ }
+
+ UndoRedo &ur = editor_data->get_undo_redo();
+ ur.create_action(TTR("Paste Node(s)"));
+ ur.add_do_method(editor_selection, "clear");
+
+ Map<RES, RES> resource_remap;
+ String target_scene;
+ if (edited_scene) {
+ target_scene = edited_scene->get_scene_file_path();
+ }
+ if (target_scene != clipboard_source_scene) {
+ if (!clipboard_resource_remap.has(target_scene)) {
+ Map<RES, RES> remap;
+ for (Node *E : node_clipboard) {
+ _create_remap_for_node(E, remap);
+ }
+ clipboard_resource_remap[target_scene] = remap;
+ }
+ resource_remap = clipboard_resource_remap[target_scene];
+ }
+
+ for (Node *node : node_clipboard) {
+ Map<const Node *, Node *> duplimap;
+
+ Node *dup = node->duplicate_from_editor(duplimap, resource_remap);
+ ERR_CONTINUE(!dup);
+
+ pasted_nodes.push_back(dup);
+
+ if (!paste_parent) {
+ paste_parent = dup;
+ owner = dup;
+ ur.add_do_method(editor, "set_edited_scene", dup);
+ } else {
+ ur.add_do_method(paste_parent, "add_child", dup, true);
+ }
+
+ for (KeyValue<const Node *, Node *> &E2 : duplimap) {
+ Node *d = E2.value;
+ if (d != dup) {
+ ur.add_do_method(d, "set_owner", owner);
+ }
+ }
+
+ if (dup != owner) {
+ ur.add_do_method(dup, "set_owner", owner);
+ }
+ ur.add_do_method(editor_selection, "add_node", dup);
+
+ if (dup == paste_parent) {
+ ur.add_undo_method(editor, "set_edited_scene", (Object *)nullptr);
+ } else {
+ ur.add_undo_method(paste_parent, "remove_child", dup);
+ }
+ ur.add_do_reference(dup);
+
+ if (node_clipboard.size() == 1) {
+ ur.add_do_method(editor, "push_item", dup);
+ }
+ }
+
+ ur.commit_action();
+ return pasted_nodes;
+}
+
void SceneTreeDock::add_remote_tree_editor(Control *p_remote) {
ERR_FAIL_COND(remote_tree != nullptr);
add_child(p_remote);
@@ -3101,6 +3159,7 @@ void SceneTreeDock::_update_create_root_dialog() {
beginner_nodes->show();
favorite_nodes->hide();
}
+ button_clipboard->set_visible(!node_clipboard.is_empty());
}
}
@@ -3248,7 +3307,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KeyModifierMask::CMD | Key::A);
ED_SHORTCUT("scene_tree/instance_scene", TTR("Instantiate Child Scene"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::A);
- ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse All"));
+ ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse Branch"));
ED_SHORTCUT("scene_tree/cut_node", TTR("Cut"), KeyModifierMask::CMD | Key::X);
ED_SHORTCUT("scene_tree/copy_node", TTR("Copy"), KeyModifierMask::CMD | Key::C);
ED_SHORTCUT("scene_tree/paste_node", TTR("Paste"), KeyModifierMask::CMD | Key::V);
@@ -3305,11 +3364,15 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
filter_hbc->add_child(button_detach_script);
button_detach_script->hide();
- button_tree_menu = memnew(Button);
+ button_tree_menu = memnew(MenuButton);
button_tree_menu->set_flat(true);
- button_tree_menu->connect("pressed", callable_mp(this, &SceneTreeDock::_open_tree_menu));
+ button_tree_menu->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_update_tree_menu));
filter_hbc->add_child(button_tree_menu);
+ PopupMenu *tree_menu = button_tree_menu->get_popup();
+ tree_menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND);
+ tree_menu->connect("id_pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(false));
+
button_hb = memnew(HBoxContainer);
vbc->add_child(button_hb);