diff options
Diffstat (limited to 'editor/scene_tree_dock.cpp')
-rw-r--r-- | editor/scene_tree_dock.cpp | 297 |
1 files changed, 195 insertions, 102 deletions
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 16f1575757..71e93750f0 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -250,22 +250,37 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) return; } + UndoRedo *undo_redo = editor->get_undo_redo(); + undo_redo->create_action(TTR("Replace with Branch Scene")); + Node *parent = base->get_parent(); int pos = base->get_index(); - parent->remove_child(base); - parent->add_child(instanced_scene); - parent->move_child(instanced_scene, pos); - instanced_scene->set_owner(edited_scene); - editor_selection->clear(); - editor_selection->add_node(instanced_scene); - scene_tree->set_selected(instanced_scene); - - // Delete the node as late as possible because before another one is selected - // an editor plugin could be referencing it to do something with it before - // switching to another (or to none); and since some steps of changing the - // editor state are deferred, the safest thing is to do this is as the last - // step of this function and also by enqueing instead of memdelete()-ing it here - base->queue_delete(); + undo_redo->add_do_method(parent, "remove_child", base); + undo_redo->add_undo_method(parent, "remove_child", instanced_scene); + undo_redo->add_do_method(parent, "add_child", instanced_scene); + undo_redo->add_undo_method(parent, "add_child", base); + undo_redo->add_do_method(parent, "move_child", instanced_scene, pos); + undo_redo->add_undo_method(parent, "move_child", base, pos); + + List<Node *> owned; + base->get_owned_by(base->get_owner(), &owned); + Array owners; + for (List<Node *>::Element *F = owned.front(); F; F = F->next()) { + owners.push_back(F->get()); + } + undo_redo->add_do_method(instanced_scene, "set_owner", edited_scene); + undo_redo->add_undo_method(this, "_set_owners", edited_scene, owners); + + undo_redo->add_do_method(editor_selection, "clear"); + undo_redo->add_undo_method(editor_selection, "clear"); + undo_redo->add_do_method(editor_selection, "add_node", instanced_scene); + undo_redo->add_undo_method(editor_selection, "add_node", base); + undo_redo->add_do_property(scene_tree, "set_selected", instanced_scene); + undo_redo->add_undo_property(scene_tree, "set_selected", base); + + undo_redo->add_do_reference(instanced_scene); + undo_redo->add_undo_reference(base); + undo_redo->commit_action(); } bool SceneTreeDock::_cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) { @@ -325,8 +340,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (!profile_allow_editing) { break; } - Tree *tree = scene_tree->get_scene_tree(); - if (tree->is_anything_selected()) { + if (editor_selection->get_selected_node_list().size() > 1) { rename_dialog->popup_centered(); } } break; @@ -406,53 +420,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { create_dialog->popup_create(false, true, selected->get_class()); } break; + case TOOL_EXTEND_SCRIPT: { + attach_script_to_selected(true); + } break; case TOOL_ATTACH_SCRIPT: { - - if (!profile_allow_script_editing) { - break; - } - - List<Node *> selection = editor_selection->get_selected_node_list(); - if (selection.empty()) - break; - - Node *selected = scene_tree->get_selected(); - if (!selected) - selected = selection.front()->get(); - - Ref<Script> existing = selected->get_script(); - - String path = selected->get_filename(); - if (path == "") { - String root_path = editor_data->get_edited_scene_root()->get_filename(); - if (root_path == "") { - path = String("res://").plus_file(selected->get_name()); - } else { - path = root_path.get_base_dir().plus_file(selected->get_name()); - } - } - - String inherits = selected->get_class(); - if (existing.is_valid()) { - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptLanguage *l = ScriptServer::get_language(i); - if (l->get_type() == existing->get_class()) { - String name = l->get_global_class_name(existing->get_path()); - if (ScriptServer::is_global_class(name) && EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) { - inherits = name; - } else if (l->can_inherit_from_file()) { - inherits = "\"" + existing->get_path() + "\""; - } - break; - } - } - } - script_create_dialog->connect("script_created", this, "_script_created"); - script_create_dialog->connect("popup_hide", this, "_script_creation_closed"); - script_create_dialog->set_inheritance_base_type("Node"); - script_create_dialog->config(inherits, path); - script_create_dialog->popup_centered(); - + attach_script_to_selected(false); } break; case TOOL_CLEAR_SCRIPT: { @@ -699,9 +671,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { editor_data->get_undo_redo().create_action(TTR("Make node as Root")); editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node); - editor_data->get_undo_redo().add_do_method(root->get_parent(), "remove_child", root); - editor_data->get_undo_redo().add_do_method(node, "add_child", root); editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", node); + editor_data->get_undo_redo().add_do_method(node, "add_child", root); editor_data->get_undo_redo().add_do_method(node, "set_filename", root->get_filename()); editor_data->get_undo_redo().add_do_method(root, "set_filename", String()); editor_data->get_undo_redo().add_do_method(node, "set_owner", (Object *)NULL); @@ -713,14 +684,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { editor_data->get_undo_redo().add_undo_method(node, "remove_child", root); editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", root); editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node); + editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, node->get_index()); editor_data->get_undo_redo().add_undo_method(root, "set_owner", (Object *)NULL); editor_data->get_undo_redo().add_undo_method(node, "set_owner", root); - _node_replace_owner(root, root, root, MODE_UNDO); editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_undo_reference(root); editor_data->get_undo_redo().commit_action(); } break; case TOOL_MULTI_EDIT: { @@ -759,8 +729,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { _delete_confirm(); } else { - if (remove_list.size() > 1) { + if (remove_list.size() >= 2) { delete_dialog->set_text(vformat(TTR("Delete %d nodes?"), remove_list.size())); + } else if (remove_list.size() == 1 && remove_list[0] == editor_data->get_edited_scene_root()) { + delete_dialog->set_text(vformat(TTR("Delete the root node \"%s\"?"), remove_list[0]->get_name())); + } else if (remove_list.size() == 1 && remove_list[0]->get_filename() == "" && remove_list[0]->get_child_count() >= 1) { + // Display this message only for non-instanced scenes + delete_dialog->set_text(vformat(TTR("Delete node \"%s\" and its children?"), remove_list[0]->get_name())); } else { delete_dialog->set_text(vformat(TTR("Delete node \"%s\"?"), remove_list[0]->get_name())); } @@ -890,16 +865,22 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (e) { Node *node = e->get(); if (node) { + bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node); bool placeholder = node->get_scene_instance_load_placeholder(); + + // 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->popup_centered_minsize(); + break; + } + placeholder = !placeholder; - int editable_item_idx = menu->get_item_idx_from_text(TTR("Editable Children")); - int placeholder_item_idx = menu->get_item_idx_from_text(TTR("Load As Placeholder")); + if (placeholder) EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, false); node->set_scene_instance_load_placeholder(placeholder); - menu->set_item_checked(editable_item_idx, false); - menu->set_item_checked(placeholder_item_idx, placeholder); scene_tree->update_tree(); } } @@ -1504,7 +1485,7 @@ bool SceneTreeDock::_validate_no_foreign() { // When edited_scene inherits from another one the root Node will be the parent Scene, // we don't want to consider that Node a foreign one otherwise we would not be able to - // delete it + // delete it. if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene == E->get()) { continue; } @@ -1528,7 +1509,7 @@ void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.empty()) - return; //nothing to reparent + return; // Nothing to reparent. Vector<Node *> nodes; @@ -1544,18 +1525,32 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V Node *new_parent = p_new_parent; ERR_FAIL_COND(!new_parent); + if (p_nodes.size() == 0) + return; // Nothing to reparent. + + p_nodes.sort_custom<Node::Comparator>(); //Makes result reliable. + + bool no_change = true; + for (int ni = 0; ni < p_nodes.size(); ni++) { + + if (p_nodes[ni] == p_new_parent) + return; // Attempt to reparent to itself. + + if (p_nodes[ni]->get_parent() != p_new_parent || p_position_in_parent + ni != p_nodes[ni]->get_position_in_parent()) + no_change = false; + } + + if (no_change) + return; // Position and parent didn't change. + Node *validate = new_parent; while (validate) { - ERR_FAIL_COND_MSG(p_nodes.find(validate) != -1, "Selection changed at some point.. can't reparent."); + ERR_FAIL_COND_MSG(p_nodes.find(validate) != -1, "Selection changed at some point. Can't reparent."); validate = validate->get_parent(); } - //ok all valid - if (p_nodes.size() == 0) - return; //nothing to reparent - - //sort by tree order, so re-adding is easy + // Sort by tree order, so re-adding is easy. p_nodes.sort_custom<Node::Comparator>(); editor_data->get_undo_redo().create_action(TTR("Reparent Node")); @@ -1567,7 +1562,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V for (int ni = 0; ni < p_nodes.size(); ni++) { - //no undo for now, sorry + // No undo implemented for this yet. Node *node = p_nodes[ni]; fill_path_renames(node, new_parent, &path_renames); @@ -1577,14 +1572,11 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V node->get_owned_by(node->get_owner(), &owned); Array owners; for (List<Node *>::Element *E = owned.front(); E; E = E->next()) { - owners.push_back(E->get()); } - if (new_parent == node->get_parent() && node->get_index() < p_position_in_parent + ni) { - //if child will generate a gap when moved, adjust - inc--; - } + if (new_parent == node->get_parent() && node->get_index() < p_position_in_parent + ni) + inc--; // If the child will generate a gap when moved, adjust. editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node); editor_data->get_undo_redo().add_do_method(new_parent, "add_child", node); @@ -1596,17 +1588,17 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V String old_name = former_names[ni]; String new_name = new_parent->validate_child_name(node); - // name was modified, fix the path renames + // Name was modified, fix the path renames. if (old_name.casecmp_to(new_name) != 0) { - // Fix the to name to have the new name + // Fix the to name to have the new name. NodePath old_new_name = path_renames[ni].second; NodePath new_path; Vector<StringName> unfixed_new_names = old_new_name.get_names(); Vector<StringName> fixed_new_names; - // Get last name and replace with fixed new name + // Get last name and replace with fixed new name. for (int a = 0; a < (unfixed_new_names.size() - 1); a++) { fixed_new_names.push_back(unfixed_new_names[a]); } @@ -1640,8 +1632,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V inc++; } - //add and move in a second step.. (so old order is preserved) - + // Add and move in a second step (so old order is preserved). for (int ni = 0; ni < p_nodes.size(); ni++) { Node *node = p_nodes[ni]; @@ -1761,6 +1752,25 @@ void SceneTreeDock::_toggle_editable_children_from_selection() { } } +void SceneTreeDock::_toggle_placeholder_from_selection() { + + List<Node *> selection = editor_selection->get_selected_node_list(); + List<Node *>::Element *e = selection.front(); + + if (e) { + Node *node = e->get(); + if (node) { + _toggle_editable_children(node); + + bool placeholder = node->get_scene_instance_load_placeholder(); + placeholder = !placeholder; + + node->set_scene_instance_load_placeholder(placeholder); + scene_tree->update_tree(); + } + } +} + void SceneTreeDock::_toggle_editable_children(Node *p_node) { if (p_node) { @@ -2393,6 +2403,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } List<Node *> selection = editor_selection->get_selected_node_list(); + List<Node *> full_selection = editor_selection->get_full_selected_node_list(); // Above method only returns nodes with common parent. if (selection.size() == 0) return; @@ -2427,22 +2438,40 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } if (profile_allow_script_editing) { + bool add_separator = false; - if (selection.size() == 1) { - if (!existing_script.is_valid()) { - menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); - } else { - menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_ATTACH_SCRIPT); + if (full_selection.size() == 1) { + add_separator = true; + menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); + if (existing_script.is_valid()) { + menu->add_icon_shortcut(get_icon("ScriptExtend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/extend_script"), TOOL_EXTEND_SCRIPT); } } - if (selection.size() > 1 || (existing_script.is_valid() && exisiting_script_removable)) { + if (existing_script.is_valid() && exisiting_script_removable) { + add_separator = true; menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); + } else if (full_selection.size() > 1) { + bool script_exists = false; + for (List<Node *>::Element *E = full_selection.front(); E; E = E->next()) { + if (!E->get()->get_script().is_null()) { + script_exists = true; + break; + } + } + + if (script_exists) { + add_separator = true; + menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); + } + } + + if (add_separator) { + menu->add_separator(); } - menu->add_separator(); } if (profile_allow_editing) { - if (selection.size() == 1) { + if (full_selection.size() == 1) { menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); } menu->add_icon_shortcut(get_icon("Reload", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE); @@ -2454,7 +2483,9 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("Duplicate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/duplicate"), TOOL_DUPLICATE); menu->add_icon_shortcut(get_icon("Reparent", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent"), TOOL_REPARENT); menu->add_icon_shortcut(get_icon("ReparentToNewNode", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/reparent_to_new_node"), TOOL_REPARENT_TO_NEW_NODE); - menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); + if (selection.size() == 1) { + menu->add_icon_shortcut(get_icon("NewRoot", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/make_root"), TOOL_MAKE_ROOT); + } } } if (selection.size() == 1) { @@ -2463,9 +2494,11 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_separator(); menu->add_icon_shortcut(get_icon("Blend", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/merge_from_scene"), TOOL_MERGE_FROM_SCENE); menu->add_icon_shortcut(get_icon("CreateNewSceneFrom", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/save_branch_as_scene"), TOOL_NEW_SCENE_FROM); + } + if (full_selection.size() == 1) { menu->add_separator(); + menu->add_icon_shortcut(get_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); } - menu->add_icon_shortcut(get_icon("CopyNodePath", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); bool is_external = (selection[0]->get_filename() != ""); if (is_external) { @@ -2542,10 +2575,64 @@ void SceneTreeDock::_focus_node() { } } -void SceneTreeDock::open_script_dialog(Node *p_for_node) { +void SceneTreeDock::attach_script_to_selected(bool p_extend) { + if (!profile_allow_script_editing) { + return; + } + + List<Node *> selection = editor_selection->get_selected_node_list(); + if (selection.empty()) + return; + + Node *selected = scene_tree->get_selected(); + if (!selected) + selected = selection.front()->get(); + + Ref<Script> existing = selected->get_script(); + + String path = selected->get_filename(); + if (path == "") { + String root_path = editor_data->get_edited_scene_root()->get_filename(); + if (root_path == "") { + path = String("res://").plus_file(selected->get_name()); + } else { + path = root_path.get_base_dir().plus_file(selected->get_name()); + } + } + + String inherits = selected->get_class(); + + if (p_extend && existing.is_valid()) { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptLanguage *l = ScriptServer::get_language(i); + if (l->get_type() == existing->get_class()) { + String name = l->get_global_class_name(existing->get_path()); + if (ScriptServer::is_global_class(name) && EDITOR_GET("interface/editors/derive_script_globals_by_name").operator bool()) { + inherits = name; + } else if (l->can_inherit_from_file()) { + inherits = "\"" + existing->get_path() + "\""; + } + break; + } + } + } + + script_create_dialog->connect("script_created", this, "_script_created"); + script_create_dialog->connect("popup_hide", this, "_script_creation_closed"); + script_create_dialog->set_inheritance_base_type("Node"); + script_create_dialog->config(inherits, path); + script_create_dialog->popup_centered(); +} + +void SceneTreeDock::open_script_dialog(Node *p_for_node, bool p_extend) { scene_tree->set_selected(p_for_node, false); - _tool_selected(TOOL_ATTACH_SCRIPT); + + if (p_extend) { + _tool_selected(TOOL_EXTEND_SCRIPT); + } else { + _tool_selected(TOOL_ATTACH_SCRIPT); + } } void SceneTreeDock::add_remote_tree_editor(Control *p_remote) { @@ -2698,6 +2785,7 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_nodes_drag_begin"), &SceneTreeDock::_nodes_drag_begin); ClassDB::bind_method(D_METHOD("_delete_confirm"), &SceneTreeDock::_delete_confirm); ClassDB::bind_method(D_METHOD("_toggle_editable_children_from_selection"), &SceneTreeDock::_toggle_editable_children_from_selection); + ClassDB::bind_method(D_METHOD("_toggle_placeholder_from_selection"), &SceneTreeDock::_toggle_placeholder_from_selection); ClassDB::bind_method(D_METHOD("_node_prerenamed"), &SceneTreeDock::_node_prerenamed); ClassDB::bind_method(D_METHOD("_import_subscene"), &SceneTreeDock::_import_subscene); ClassDB::bind_method(D_METHOD("_selection_changed"), &SceneTreeDock::_selection_changed); @@ -2871,6 +2959,10 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel add_child(editable_instance_remove_dialog); editable_instance_remove_dialog->connect("confirmed", this, "_toggle_editable_children_from_selection"); + placeholder_editable_instance_remove_dialog = memnew(ConfirmationDialog); + add_child(placeholder_editable_instance_remove_dialog); + placeholder_editable_instance_remove_dialog->connect("confirmed", this, "_toggle_placeholder_from_selection"); + import_subscene_dialog = memnew(EditorSubScene); add_child(import_subscene_dialog); import_subscene_dialog->connect("subscene_selected", this, "_import_subscene"); @@ -2903,5 +2995,6 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel profile_allow_script_editing = true; EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true); + EDITOR_DEF("interface/editors/derive_script_globals_by_name", true); EDITOR_DEF("_use_favorites_root_selection", false); } |