/*************************************************************************/ /* scene_tree_dock.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* http://www.godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "scene_tree_dock.h" #include "editor_node.h" #include "globals.h" #include "os/keyboard.h" #include "scene/resources/packed_scene.h" #include "editor_settings.h" #include "tools/editor/plugins/canvas_item_editor_plugin.h" #include "script_editor_debugger.h" #include "tools/editor/plugins/script_editor_plugin.h" #include "core/io/resource_saver.h" #include "multi_node_edit.h" #include "tools/editor/plugins/animation_player_editor_plugin.h" #include "animation_editor.h" #include "scene/main/viewport.h" void SceneTreeDock::_unhandled_key_input(InputEvent p_event) { if (get_viewport()->get_modal_stack_top()) return; //ignore because of modal window if (!p_event.key.pressed || p_event.key.echo) return; if (ED_IS_SHORTCUT("scene_tree/add_child_node", p_event)) { _tool_selected(TOOL_NEW); } else if (ED_IS_SHORTCUT("scene_tree/instance_scene", p_event)) { _tool_selected(TOOL_INSTANCE); } else if (ED_IS_SHORTCUT("scene_tree/change_node_type", p_event)) { _tool_selected(TOOL_REPLACE); } else if (ED_IS_SHORTCUT("scene_tree/duplicate", p_event)) { _tool_selected(TOOL_DUPLICATE); } else if (ED_IS_SHORTCUT("scene_tree/add_script", p_event)) { _tool_selected(TOOL_SCRIPT); } else if (ED_IS_SHORTCUT("scene_tree/move_up", p_event)) { _tool_selected(TOOL_MOVE_UP); } else if (ED_IS_SHORTCUT("scene_tree/move_down", p_event)) { _tool_selected(TOOL_MOVE_DOWN); } else if (ED_IS_SHORTCUT("scene_tree/reparent", p_event)) { _tool_selected(TOOL_REPARENT); } else if (ED_IS_SHORTCUT("scene_tree/merge_from_scene", p_event)) { _tool_selected(TOOL_MERGE_FROM_SCENE); } else if (ED_IS_SHORTCUT("scene_tree/save_branch_as_scene", p_event)) { _tool_selected(TOOL_NEW_SCENE_FROM); } else if (ED_IS_SHORTCUT("scene_tree/delete_no_confirm", p_event)) { _tool_selected(TOOL_ERASE, true); } else if (ED_IS_SHORTCUT("scene_tree/delete", p_event)) { _tool_selected(TOOL_ERASE); } } void SceneTreeDock::instance(const String& p_file) { Node *parent = scene_tree->get_selected(); if (!parent || !edited_scene) { current_option=-1; //accept->get_cancel()->hide(); accept->get_ok()->set_text(TTR("OK :(")); accept->set_text(TTR("No parent to instance a child at.")); accept->popup_centered_minsize(); return; }; ERR_FAIL_COND(!parent); Vector scenes; scenes.push_back(p_file); _perform_instance_scenes(scenes,parent,-1); } void SceneTreeDock::instance_scenes(const Vector& p_files, Node *p_parent) { Node *parent = p_parent; if (!parent) { parent = scene_tree->get_selected(); } if (!parent || !edited_scene) { accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("No parent to instance the scenes at.")); accept->popup_centered_minsize(); return; }; _perform_instance_scenes(p_files, parent, -1); } void SceneTreeDock::_perform_instance_scenes(const Vector& p_files,Node* parent,int p_pos) { ERR_FAIL_COND(!parent); Vector instances; bool error=false; for(int i=0;i sdata = ResourceLoader::load(p_files[i]); if (!sdata.is_valid()) { current_option=-1; //accept->get_cancel()->hide(); accept->get_ok()->set_text(TTR("Ugh")); accept->set_text(vformat(TTR("Error loading scene from %s"),p_files[i])); accept->popup_centered_minsize(); error=true; break; } Node*instanced_scene=sdata->instance(true); if (!instanced_scene) { current_option=-1; //accept->get_cancel()->hide(); accept->get_ok()->set_text(TTR("Ugh")); accept->set_text(vformat(TTR("Error instancing scene from %s"),p_files[i])); accept->popup_centered_minsize(); error=true; break; } if (edited_scene->get_filename()!="") { if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) { accept->get_ok()->set_text(TTR("Ok")); accept->set_text(vformat(TTR("Cannot instance the scene '%s' because the current scene exists within one of its nodes."),p_files[i])); accept->popup_centered_minsize(); error=true; break; } } instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_files[i]) ); instances.push_back(instanced_scene); } if (error) { for(int i=0;igenerate_instance_state(); editor_data->get_undo_redo().create_action(TTR("Instance Scene(s)")); for(int i=0;iget_undo_redo().add_do_method(parent,"add_child",instanced_scene); if (p_pos>=0) { editor_data->get_undo_redo().add_do_method(parent,"move_child",instanced_scene,p_pos+i); } editor_data->get_undo_redo().add_do_method(instanced_scene,"set_owner",edited_scene); editor_data->get_undo_redo().add_do_method(editor_selection,"clear"); editor_data->get_undo_redo().add_do_method(editor_selection,"add_node",instanced_scene); editor_data->get_undo_redo().add_do_reference(instanced_scene); editor_data->get_undo_redo().add_undo_method(parent,"remove_child",instanced_scene); String new_name = parent->validate_child_name(instanced_scene->get_name()); ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); editor_data->get_undo_redo().add_do_method(sed,"live_debug_instance_node",edited_scene->get_path_to(parent),p_files[i],new_name); editor_data->get_undo_redo().add_undo_method(sed,"live_debug_remove_node",NodePath(String(edited_scene->get_path_to(parent))+"/"+new_name)); } editor_data->get_undo_redo().commit_action(); } void SceneTreeDock::_replace_with_branch_scene(const String& p_file,Node* base) { Ref sdata = ResourceLoader::load(p_file); if (!sdata.is_valid()) { accept->get_ok()->set_text(TTR("Ugh")); accept->set_text(vformat(TTR("Error loading scene from %s"),p_file)); accept->popup_centered_minsize(); return; } Node *instanced_scene=sdata->instance(true); if (!instanced_scene) { accept->get_ok()->set_text(TTR("Ugh")); accept->set_text(vformat(TTR("Error instancing scene from %s"),p_file)); accept->popup_centered_minsize(); return; } Node *parent = base->get_parent(); int pos = base->get_index(); memdelete(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); } bool SceneTreeDock::_cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node) { int childCount = p_desired_node->get_child_count(); if (p_desired_node->get_filename()==p_target_scene_path) { return true; } for (int i=0;iget_child(i); if(_cyclical_dependency_exists(p_target_scene_path,child)) { return true; } } return false; } static String _get_name_num_separator() { switch(EditorSettings::get_singleton()->get("scenetree_editor/duplicate_node_name_num_separator").operator int()) { case 0: return ""; case 1: return " "; case 2: return "_"; case 3: return "-"; } return " "; } void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { current_option=p_tool; switch(p_tool) { case TOOL_NEW: { //if (!_validate_no_foreign()) // break; create_dialog->popup(true); } break; case TOOL_INSTANCE: { Node *scene = edited_scene; if (!scene) { EditorNode::get_singleton()->new_inherited_scene(); /* should be legal now current_option=-1; //confirmation->get_cancel()->hide(); accept->get_ok()->set_text("I see.."); accept->set_text("This operation can't be done without a tree root."); accept->popup_centered_minsize(); */ break; } //if (!_validate_no_foreign()) // break; file->set_mode(EditorFileDialog::MODE_OPEN_FILE); List extensions; ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions); file->clear_filters(); for(int i=0;iadd_filter("*."+extensions[i]+" ; "+extensions[i].to_upper()); } //file->set_current_path(current_path); file->popup_centered_ratio(); } break; case TOOL_REPLACE: { create_dialog->popup(false); } break; case TOOL_CONNECT: { Node *current = scene_tree->get_selected(); if (!current) break; //if (!_validate_no_foreign()) // break; //connect_dialog->popup_centered_ratio(); //connect_dialog->set_node(current); } break; case TOOL_GROUP: { Node *current = scene_tree->get_selected(); if (!current) break; //if (!_validate_no_foreign()) // break; //groups_editor->set_current(current); //groups_editor->popup_centered_ratio(); } break; case TOOL_SCRIPT: { Node *selected = scene_tree->get_selected(); if (!selected) break; //if (!_validate_no_foreign()) // break; Ref