You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-09 12:50:35 +00:00
Improve node pasting
This commit is contained in:
@@ -445,8 +445,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool was_empty = false;
|
||||||
if (!node_clipboard.is_empty()) {
|
if (!node_clipboard.is_empty()) {
|
||||||
_clear_clipboard();
|
_clear_clipboard();
|
||||||
|
} else {
|
||||||
|
was_empty = true;
|
||||||
}
|
}
|
||||||
clipboard_source_scene = editor->get_edited_scene()->get_scene_file_path();
|
clipboard_source_scene = editor->get_edited_scene()->get_scene_file_path();
|
||||||
|
|
||||||
@@ -464,81 +467,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||||||
if (p_tool == TOOL_CUT) {
|
if (p_tool == TOOL_CUT) {
|
||||||
_delete_confirm(true);
|
_delete_confirm(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (was_empty) {
|
||||||
|
_update_create_root_dialog();
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
case TOOL_PASTE: {
|
case TOOL_PASTE: {
|
||||||
if (node_clipboard.is_empty() || !edited_scene) {
|
paste_nodes();
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
} break;
|
||||||
case TOOL_REPLACE: {
|
case TOOL_REPLACE: {
|
||||||
if (!profile_allow_editing) {
|
if (!profile_allow_editing) {
|
||||||
@@ -1306,6 +1241,12 @@ void SceneTreeDock::_notification(int p_what) {
|
|||||||
button_custom->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
|
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_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();
|
node_shortcuts->add_spacer();
|
||||||
create_root_dialog->add_child(node_shortcuts);
|
create_root_dialog->add_child(node_shortcuts);
|
||||||
_update_create_root_dialog();
|
_update_create_root_dialog();
|
||||||
@@ -1330,6 +1271,7 @@ void SceneTreeDock::_notification(int p_what) {
|
|||||||
button_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
|
button_3d->set_icon(get_theme_icon(SNAME("Node3D"), SNAME("EditorIcons")));
|
||||||
button_ui->set_icon(get_theme_icon(SNAME("Control"), 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_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_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
|
||||||
filter->set_clear_button_enabled(true);
|
filter->set_clear_button_enabled(true);
|
||||||
@@ -2740,10 +2682,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (profile_allow_editing) {
|
if (profile_allow_editing) {
|
||||||
menu->add_shortcut(ED_GET_SHORTCUT("scene_tree/cut_node"), TOOL_CUT);
|
menu->add_icon_shortcut(get_theme_icon(SNAME("ActionCut"), SNAME("EditorIcons")), 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("ActionCopy"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
|
||||||
if (selection.size() == 1 && !node_clipboard.is_empty()) {
|
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();
|
menu->add_separator();
|
||||||
}
|
}
|
||||||
@@ -3022,6 +2964,108 @@ void SceneTreeDock::open_instance_child_dialog() {
|
|||||||
_tool_selected(TOOL_INSTANTIATE, true);
|
_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) {
|
void SceneTreeDock::add_remote_tree_editor(Control *p_remote) {
|
||||||
ERR_FAIL_COND(remote_tree != nullptr);
|
ERR_FAIL_COND(remote_tree != nullptr);
|
||||||
add_child(p_remote);
|
add_child(p_remote);
|
||||||
@@ -3121,6 +3165,7 @@ void SceneTreeDock::_update_create_root_dialog() {
|
|||||||
beginner_nodes->show();
|
beginner_nodes->show();
|
||||||
favorite_nodes->hide();
|
favorite_nodes->hide();
|
||||||
}
|
}
|
||||||
|
button_clipboard->set_visible(!node_clipboard.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ class SceneTreeDock : public VBoxContainer {
|
|||||||
Button *button_3d;
|
Button *button_3d;
|
||||||
Button *button_ui;
|
Button *button_ui;
|
||||||
Button *button_custom;
|
Button *button_custom;
|
||||||
|
Button *button_clipboard;
|
||||||
|
|
||||||
HBoxContainer *button_hb;
|
HBoxContainer *button_hb;
|
||||||
Button *edit_local, *edit_remote;
|
Button *edit_local, *edit_remote;
|
||||||
@@ -308,6 +309,8 @@ public:
|
|||||||
void open_add_child_dialog();
|
void open_add_child_dialog();
|
||||||
void open_instance_child_dialog();
|
void open_instance_child_dialog();
|
||||||
|
|
||||||
|
List<Node *> paste_nodes();
|
||||||
|
|
||||||
ScriptCreateDialog *get_script_create_dialog() { return script_create_dialog; }
|
ScriptCreateDialog *get_script_create_dialog() { return script_create_dialog; }
|
||||||
|
|
||||||
SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data);
|
SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSelection *p_editor_selection, EditorData &p_editor_data);
|
||||||
|
|||||||
Reference in New Issue
Block a user