diff options
Diffstat (limited to 'editor/scene_tree_dock.cpp')
-rw-r--r-- | editor/scene_tree_dock.cpp | 247 |
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); |