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.cpp2061
1 files changed, 2061 insertions, 0 deletions
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
new file mode 100644
index 0000000000..47eb84ab79
--- /dev/null
+++ b/editor/scene_tree_dock.cpp
@@ -0,0 +1,2061 @@
+/*************************************************************************/
+/* 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 "global_config.h"
+#include "os/keyboard.h"
+#include "scene/resources/packed_scene.h"
+#include "editor_settings.h"
+#include "editor/plugins/canvas_item_editor_plugin.h"
+#include "editor/plugins/spatial_editor_plugin.h"
+#include "script_editor_debugger.h"
+#include "editor/plugins/script_editor_plugin.h"
+#include "core/io/resource_saver.h"
+#include "multi_node_edit.h"
+#include "editor/plugins/animation_player_editor_plugin.h"
+#include "animation_editor.h"
+#include "scene/main/viewport.h"
+
+
+void SceneTreeDock::_nodes_drag_begin() {
+
+
+ if (restore_script_editor_on_drag) {
+ EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);
+ restore_script_editor_on_drag=false;
+ }
+
+}
+
+void SceneTreeDock::_input(InputEvent p_event) {
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) {
+ restore_script_editor_on_drag=false; //lost chance
+ }
+}
+
+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/attach_script", p_event)) {
+ _tool_selected(TOOL_ATTACH_SCRIPT);
+ }
+ else if(ED_IS_SHORTCUT("scene_tree/clear_script", p_event)) {
+ _tool_selected(TOOL_CLEAR_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/copy_node_path", p_event)) {
+ _tool_selected(TOOL_COPY_NODE_PATH);
+ }
+ 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<String> scenes;
+ scenes.push_back(p_file);
+ _perform_instance_scenes(scenes,parent,-1);
+
+}
+
+void SceneTreeDock::instance_scenes(const Vector<String>& 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<String>& p_files,Node* parent,int p_pos) {
+
+
+
+ ERR_FAIL_COND(!parent);
+
+
+ Vector<Node*> instances;
+
+ bool error=false;
+
+ for(int i=0;i<p_files.size();i++) {
+
+ Ref<PackedScene> 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(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ 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( GlobalConfig::get_singleton()->localize_path(p_files[i]) );
+
+ instances.push_back(instanced_scene);
+ }
+
+ if (error) {
+ for(int i=0;i<instances.size();i++) {
+ memdelete(instances[i]);
+ }
+ return;
+ }
+
+
+
+ //instanced_scene->generate_instance_state();
+
+ editor_data->get_undo_redo().create_action(TTR("Instance Scene(s)"));
+
+ for(int i=0;i<instances.size();i++) {
+
+ Node* instanced_scene=instances[i];
+
+ editor_data->get_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);
+ 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<PackedScene> 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(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ 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;i<childCount;i++) {
+ Node* child=p_desired_node->get_child(i);
+
+ if(_cyclical_dependency_exists(p_target_scene_path,child)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+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<String> extensions;
+ ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions);
+ file->clear_filters();
+ for(int i=0;i<extensions.size();i++) {
+
+ file->add_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_ATTACH_SCRIPT: {
+
+ Node *selected = scene_tree->get_selected();
+ if (!selected)
+ break;
+
+ /*
+ if (!_validate_no_foreign())
+ break;
+ */
+
+ Ref<Script> existing = selected->get_script();
+ if (existing.is_valid())
+ editor->push_item(existing.ptr());
+ else {
+ String path = selected->get_filename();
+ script_create_dialog->config(selected->get_class(),path);
+ script_create_dialog->popup_centered(Size2(300,290));
+ //script_create_dialog->popup_centered_minsize();
+
+ }
+
+ } break;
+ case TOOL_CLEAR_SCRIPT: {
+ Node *selected = scene_tree->get_selected();
+ if(!selected)
+ break;
+
+ Ref<Script> existing = selected->get_script();
+ if(existing.is_valid()) {
+ const RefPtr empty;
+ selected->set_script(empty);
+ button_create_script->show();
+ button_clear_script->hide();
+ }
+
+ } break;
+ case TOOL_MOVE_UP:
+ case TOOL_MOVE_DOWN: {
+
+ if (!scene_tree->get_selected())
+ break;
+
+
+ if (scene_tree->get_selected()==edited_scene) {
+
+
+ current_option=-1;
+ //accept->get_cancel()->hide();
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("This operation can't be done on the tree root."));
+ accept->popup_centered_minsize();
+ break;
+ }
+
+
+ if (!_validate_no_foreign())
+ break;
+
+ bool MOVING_DOWN = (p_tool == TOOL_MOVE_DOWN);
+ bool MOVING_UP = !MOVING_DOWN;
+
+ Node *common_parent = scene_tree->get_selected()->get_parent();
+ List<Node*> selection = editor_selection->get_selected_node_list();
+ selection.sort_custom<Node::Comparator>(); // sort by index
+ if (MOVING_DOWN)
+ selection.invert();
+
+ int lowest_id = common_parent->get_child_count() - 1;
+ int highest_id = 0;
+ for (List<Node*>::Element *E = selection.front(); E; E = E->next()) {
+ int index = E->get()->get_index();
+
+ if (index > highest_id) highest_id = index;
+ if (index < lowest_id) lowest_id = index;
+
+ if (E->get()->get_parent() != common_parent)
+ common_parent = NULL;
+ }
+
+ if (!common_parent || (MOVING_DOWN && highest_id >= common_parent->get_child_count() - MOVING_DOWN) || (MOVING_UP && lowest_id == 0))
+ break; // one or more nodes can not be moved
+
+ if (selection.size() == 1) editor_data->get_undo_redo().create_action(TTR("Move Node In Parent"));
+ if (selection.size() > 1) editor_data->get_undo_redo().create_action(TTR("Move Nodes In Parent"));
+
+ for (int i = 0; i < selection.size(); i++) {
+ Node *top_node = selection[i];
+ Node *bottom_node = selection[selection.size() - 1 - i];
+
+ ERR_FAIL_COND(!top_node->get_parent());
+ ERR_FAIL_COND(!bottom_node->get_parent());
+
+ int bottom_node_pos = bottom_node->get_index();
+ int top_node_pos_next = top_node->get_index() + (MOVING_DOWN ? 1 : -1);
+
+ editor_data->get_undo_redo().add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next);
+ editor_data->get_undo_redo().add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos);
+ }
+
+ editor_data->get_undo_redo().commit_action();
+
+ } break;
+ case TOOL_DUPLICATE: {
+
+ if (!edited_scene)
+ break;
+
+
+ if (editor_selection->is_selected(edited_scene)) {
+
+
+ current_option=-1;
+ //accept->get_cancel()->hide();
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("This operation can't be done on the tree root."));
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ if (!_validate_no_foreign())
+ break;
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+ if (selection.size()==0)
+ break;
+
+ List<Node*> reselect;
+
+ editor_data->get_undo_redo().create_action(TTR("Duplicate Node(s)"));
+ editor_data->get_undo_redo().add_do_method(editor_selection,"clear");
+
+ Node *dupsingle=NULL;
+
+
+ for (List<Node*>::Element *E=selection.front();E;E=E->next()) {
+
+ Node *node = E->get();
+ Node *parent = node->get_parent();
+
+ List<Node*> owned;
+ node->get_owned_by(node->get_owner(),&owned);
+
+ Map<Node*,Node*> duplimap;
+ Node * dup = _duplicate(node,duplimap);
+
+ ERR_CONTINUE(!dup);
+
+ if (selection.size()==1)
+ dupsingle=dup;
+
+ dup->set_name(parent->validate_child_name(dup));
+
+ editor_data->get_undo_redo().add_do_method(parent,"_add_child_below_node",node, dup);
+ for (List<Node*>::Element *F=owned.front();F;F=F->next()) {
+
+ if (!duplimap.has(F->get())) {
+
+ continue;
+ }
+ Node *d=duplimap[F->get()];
+ editor_data->get_undo_redo().add_do_method(d,"set_owner",node->get_owner());
+ }
+ editor_data->get_undo_redo().add_do_method(editor_selection,"add_node",dup);
+ editor_data->get_undo_redo().add_undo_method(parent,"remove_child",dup);
+ editor_data->get_undo_redo().add_do_reference(dup);
+
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_duplicate_node",edited_scene->get_path_to(node),dup->get_name());
+ editor_data->get_undo_redo().add_undo_method(sed,"live_debug_remove_node",NodePath(String(edited_scene->get_path_to(parent))+"/"+dup->get_name()));
+
+ //parent->add_child(dup);
+ //reselect.push_back(dup);
+ }
+
+ editor_data->get_undo_redo().commit_action();
+
+ if (dupsingle)
+ editor->push_item(dupsingle);
+
+
+
+
+
+ } break;
+ case TOOL_REPARENT: {
+
+
+ if (!scene_tree->get_selected())
+ break;
+
+
+ if (editor_selection->is_selected(edited_scene)) {
+
+
+ current_option=-1;
+ //confirmation->get_cancel()->hide();
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("This operation can't be done on the tree root."));
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ if (!_validate_no_foreign())
+ break;
+
+ List<Node*> nodes = editor_selection->get_selected_node_list();
+ Set<Node*> nodeset;
+ for(List<Node*>::Element *E=nodes.front();E;E=E->next()) {
+
+ nodeset.insert(E->get());
+ }
+ reparent_dialog->popup_centered_ratio();
+ reparent_dialog->set_current( nodeset );
+
+ } break;
+ case TOOL_MULTI_EDIT: {
+
+ Node*root=EditorNode::get_singleton()->get_edited_scene();
+ if (!root)
+ break;
+ Ref<MultiNodeEdit> mne = memnew( MultiNodeEdit );
+ for (const Map<Node*,Object*>::Element *E=EditorNode::get_singleton()->get_editor_selection()->get_selection().front();E;E=E->next()) {
+ mne->add_node(root->get_path_to(E->key()));
+ }
+
+ EditorNode::get_singleton()->push_item(mne.ptr());
+
+ } break;
+
+ case TOOL_ERASE: {
+
+ List<Node*> remove_list = editor_selection->get_selected_node_list();
+
+ if (remove_list.empty())
+ return;
+
+ if (!_validate_no_foreign())
+ break;
+
+ if (p_confirm_override) {
+ _delete_confirm();
+
+ // hack, force 2d editor viewport to refresh after deletion
+ if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton())
+ editor->get_viewport_control()->update();
+
+ } else {
+ delete_dialog->set_text(TTR("Delete Node(s)?"));
+ delete_dialog->popup_centered_minsize();
+ }
+
+ } break;
+ case TOOL_MERGE_FROM_SCENE: {
+
+ EditorNode::get_singleton()->merge_from_scene();
+ } break;
+ case TOOL_NEW_SCENE_FROM: {
+
+ Node *scene = editor_data->get_edited_scene_root();
+
+ if (!scene) {
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("This operation can't be done without a scene."));
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if (selection.size()!=1) {
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("This operation requires a single selected node."));
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ Node *tocopy = selection.front()->get();
+
+ if (tocopy==scene){
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("Can not perform with the root node."));
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ if (tocopy!=editor_data->get_edited_scene_root() && tocopy->get_filename()!="") {
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("This operation can't be done on instanced scenes."));
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ new_scene_from_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+
+ List<String> extensions;
+ Ref<PackedScene> sd = memnew( PackedScene );
+ ResourceSaver::get_recognized_extensions(sd,&extensions);
+ new_scene_from_dialog->clear_filters();
+ for(int i=0;i<extensions.size();i++) {
+ new_scene_from_dialog->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper());
+ }
+
+ String existing;
+ if (extensions.size()) {
+ String root_name(tocopy->get_name());
+ existing=root_name+"."+extensions.front()->get().to_lower();
+ }
+ new_scene_from_dialog->set_current_path(existing);
+
+ new_scene_from_dialog->popup_centered_ratio();
+ new_scene_from_dialog->set_title(TTR("Save New Scene As.."));
+
+ } break;
+ case TOOL_COPY_NODE_PATH: {
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if(List<Node*>::Element *e = selection.front()) {
+ if(Node *node = e->get()) {
+ Node *root = EditorNode::get_singleton()->get_edited_scene();
+ NodePath path = root->get_path().rel_path_to(node->get_path());
+ OS::get_singleton()->set_clipboard(path);
+ }
+ }
+ } break;
+ }
+
+}
+
+void SceneTreeDock::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_READY: {
+
+ if (!first_enter)
+ break;
+ first_enter=false;
+
+ CanvasItemEditorPlugin *canvas_item_plugin = editor_data->get_editor("2D")->cast_to<CanvasItemEditorPlugin>();
+ if (canvas_item_plugin) {
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_lock_status_changed", scene_tree, "_update_tree");
+ canvas_item_plugin->get_canvas_item_editor()->connect("item_group_status_changed", scene_tree, "_update_tree");
+ scene_tree->connect("node_changed", canvas_item_plugin->get_canvas_item_editor()->get_viewport_control(), "update");
+ }
+ button_add->set_icon(get_icon("Add","EditorIcons"));
+ button_instance->set_icon(get_icon("Instance","EditorIcons"));
+ button_create_script->set_icon(get_icon("ScriptCreate","EditorIcons"));
+ button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons"));
+
+
+ filter_icon->set_texture(get_icon("Zoom","EditorIcons"));
+
+ EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed",this,"_selection_changed");
+
+ } break;
+ }
+}
+
+
+void SceneTreeDock::_load_request(const String& p_path) {
+
+ editor->open_request(p_path);
+}
+
+void SceneTreeDock::_script_open_request(const Ref<Script>& p_script) {
+
+ editor->edit_resource(p_script);
+}
+
+void SceneTreeDock::_node_selected() {
+
+
+ Node *node=scene_tree->get_selected();
+
+ if (!node) {
+
+ editor->push_item(NULL);
+ return;
+ }
+
+ if (ScriptEditor::get_singleton()->is_visible_in_tree()) {
+ restore_script_editor_on_drag=true;
+ }
+
+ editor->push_item(node);
+
+
+}
+
+void SceneTreeDock::_node_renamed() {
+
+ _node_selected();
+}
+
+Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node*,Node*> &duplimap) {
+
+ Node *node=NULL;
+
+ if (p_node->get_filename()!="") { //an instance
+
+ Ref<PackedScene> sd = ResourceLoader::load( p_node->get_filename() );
+ ERR_FAIL_COND_V(!sd.is_valid(),NULL);
+ node = sd->instance(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ ERR_FAIL_COND_V(!node,NULL);
+ node->set_scene_instance_load_placeholder(p_node->get_scene_instance_load_placeholder());
+ //node->generate_instance_state();
+ } else {
+ Object *obj = ClassDB::instance(p_node->get_class());
+ ERR_FAIL_COND_V(!obj,NULL);
+ node = obj->cast_to<Node>();
+ if (!node)
+ memdelete(obj);
+ ERR_FAIL_COND_V(!node,NULL);
+
+ }
+
+ List<PropertyInfo> plist;
+
+ p_node->get_property_list(&plist);
+
+ for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
+
+ if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
+ continue;
+ String name = E->get().name;
+ node->set( name, p_node->get(name) );
+
+ }
+
+
+ List<Node::GroupInfo> group_info;
+ p_node->get_groups(&group_info);
+ for (List<Node::GroupInfo>::Element *E=group_info.front();E;E=E->next()) {
+
+ if (E->get().persistent)
+ node->add_to_group(E->get().name,true);
+ }
+
+
+ node->set_name(p_node->get_name());
+ duplimap[p_node]=node;
+
+ for(int i=0;i<p_node->get_child_count();i++) {
+
+ Node *child = p_node->get_child(i);
+ if (p_node->get_owner()!=child->get_owner())
+ continue; //don't bother with not in-scene nodes.
+
+ Node *dup = _duplicate(child,duplimap);
+ if (!dup) {
+ memdelete(node);
+ return NULL;
+ }
+
+ node->add_child(dup);
+ }
+
+ return node;
+
+}
+
+
+void SceneTreeDock::_set_owners(Node *p_owner, const Array& p_nodes) {
+
+ for(int i=0;i<p_nodes.size();i++) {
+
+ Object *obj=p_nodes[i];
+ if (!obj)
+ continue;
+
+ Node *n=obj->cast_to<Node>();
+ if (!n)
+ continue;
+ n->set_owner(p_owner);
+ }
+}
+
+
+void SceneTreeDock::_fill_path_renames(Vector<StringName> base_path,Vector<StringName> new_base_path,Node * p_node, List<Pair<NodePath,NodePath> > *p_renames) {
+
+ base_path.push_back(p_node->get_name());
+ if (new_base_path.size())
+ new_base_path.push_back(p_node->get_name());
+
+ NodePath from( base_path,true );
+ NodePath to;
+ if (new_base_path.size())
+ to=NodePath( new_base_path,true );
+
+ Pair<NodePath,NodePath> npp;
+ npp.first=from;
+ npp.second=to;
+
+ p_renames->push_back(npp);
+
+ for(int i=0;i<p_node->get_child_count();i++) {
+
+ _fill_path_renames(base_path,new_base_path,p_node->get_child(i),p_renames);
+ }
+
+
+}
+
+void SceneTreeDock::fill_path_renames(Node* p_node, Node *p_new_parent, List<Pair<NodePath,NodePath> > *p_renames) {
+
+ if (!bool(EDITOR_DEF("editors/animation/autorename_animation_tracks",true)))
+ return;
+
+
+ Vector<StringName> base_path;
+ Node *n = p_node->get_parent();
+ while(n) {
+ base_path.push_back(n->get_name());
+ n=n->get_parent();
+ }
+ base_path.invert();
+
+ Vector<StringName> new_base_path;
+ if (p_new_parent) {
+ n = p_new_parent;
+ while(n) {
+ new_base_path.push_back(n->get_name());
+ n=n->get_parent();
+ }
+
+ new_base_path.invert();
+ }
+
+ _fill_path_renames(base_path,new_base_path,p_node,p_renames);
+}
+
+void SceneTreeDock::perform_node_renames(Node* p_base,List<Pair<NodePath,NodePath> > *p_renames, Map<Ref<Animation>, Set<int> > *r_rem_anims) {
+
+ Map<Ref<Animation>, Set<int> > rem_anims;
+
+ if (!r_rem_anims)
+ r_rem_anims=&rem_anims;
+
+ if (!bool(EDITOR_DEF("editors/animation/autorename_animation_tracks",true)))
+ return;
+
+ if (!p_base) {
+
+ p_base=edited_scene;
+ }
+
+ if (!p_base)
+ return;
+
+
+ if (p_base->cast_to<AnimationPlayer>()) {
+
+ AnimationPlayer *ap=p_base->cast_to<AnimationPlayer>();
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ Node *root = ap->get_node(ap->get_root());
+
+
+ if (root) {
+
+
+ NodePath root_path=root->get_path();
+ NodePath new_root_path=root_path;
+
+
+ for(List<Pair<NodePath,NodePath> >::Element* E=p_renames->front();E;E=E->next()) {
+
+ if (E->get().first==root_path) {
+ new_root_path=E->get().second;
+ break;
+ }
+ }
+
+ if (new_root_path!=NodePath()) {
+ //will not be erased
+
+ for(List<StringName>::Element *E=anims.front();E;E=E->next()) {
+
+ Ref<Animation> anim=ap->get_animation(E->get());
+ if (!r_rem_anims->has(anim)) {
+ r_rem_anims->insert(anim,Set<int>());
+ Set<int> &ran = r_rem_anims->find(anim)->get();
+ for(int i=0;i<anim->get_track_count();i++)
+ ran.insert(i);
+ }
+
+ Set<int> &ran = r_rem_anims->find(anim)->get();
+
+ if (anim.is_null())
+ continue;
+
+ for(int i=0;i<anim->get_track_count();i++) {
+
+ NodePath track_np=anim->track_get_path(i);
+ Node *n = root->get_node(track_np);
+ if (!n) {
+ continue;
+ }
+
+ NodePath old_np = n->get_path();
+
+ if (!ran.has(i))
+ continue; //channel was removed
+
+ for(List<Pair<NodePath,NodePath> >::Element* E=p_renames->front();E;E=E->next()) {
+
+ if (E->get().first==old_np) {
+
+
+ if (E->get().second==NodePath()) {
+ //will be erased
+
+ int idx=0;
+ Set<int>::Element *EI=ran.front();
+ ERR_FAIL_COND(!EI); //bug
+ while(EI->get()!=i) {
+ idx++;
+ EI=EI->next();
+ ERR_FAIL_COND(!EI); //another bug
+
+ }
+
+ editor_data->get_undo_redo().add_do_method(anim.ptr(),"remove_track",idx);
+ editor_data->get_undo_redo().add_undo_method(anim.ptr(),"add_track",anim->track_get_type(i),idx);
+ editor_data->get_undo_redo().add_undo_method(anim.ptr(),"track_set_path",idx,track_np);
+ editor_data->get_undo_redo().add_undo_method(anim.ptr(),"track_set_interpolation_type",idx,anim->track_get_interpolation_type(i));
+ for(int j=0;j<anim->track_get_key_count(i);j++) {
+
+ editor_data->get_undo_redo().add_undo_method(anim.ptr(),"track_insert_key",idx,anim->track_get_key_time(i,j),anim->track_get_key_value(i,j),anim->track_get_key_transition(i,j));
+ }
+
+ ran.erase(i); //byebye channel
+
+ } else {
+ //will be renamed
+ NodePath rel_path = new_root_path.rel_path_to(E->get().second);
+
+ NodePath new_path = NodePath( rel_path.get_names(), track_np.get_subnames(), false, track_np.get_property() );
+ if (new_path==track_np)
+ continue; //bleh
+ editor_data->get_undo_redo().add_do_method(anim.ptr(),"track_set_path",i,new_path);
+ editor_data->get_undo_redo().add_undo_method(anim.ptr(),"track_set_path",i,track_np);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ for(int i=0;i<p_base->get_child_count();i++)
+ perform_node_renames(p_base->get_child(i),p_renames,r_rem_anims);
+
+}
+
+
+void SceneTreeDock::_node_prerenamed(Node* p_node, const String& p_new_name) {
+
+
+ List<Pair<NodePath,NodePath> > path_renames;
+
+ Vector<StringName> base_path;
+ Node *n = p_node->get_parent();
+ while(n) {
+ base_path.push_back(n->get_name());
+ n=n->get_parent();
+ }
+ base_path.invert();
+
+
+ Vector<StringName> new_base_path=base_path;
+ base_path.push_back(p_node->get_name());
+
+ new_base_path.push_back(p_new_name);
+
+ Pair<NodePath,NodePath> npp;
+ npp.first = NodePath(base_path,true);
+ npp.second = NodePath(new_base_path,true);
+ path_renames.push_back(npp);
+
+
+ for(int i=0;i<p_node->get_child_count();i++)
+ _fill_path_renames(base_path,new_base_path,p_node->get_child(i),&path_renames);
+
+ perform_node_renames(NULL,&path_renames);
+
+}
+
+bool SceneTreeDock::_validate_no_foreign() {
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ for (List<Node*>::Element *E=selection.front();E;E=E->next()) {
+
+ if (E->get()!=edited_scene && E->get()->get_owner()!=edited_scene) {
+
+ accept->get_ok()->set_text(TTR("Makes Sense!"));
+ accept->set_text(TTR("Can't operate on nodes from a foreign scene!"));
+ accept->popup_centered_minsize();
+ return false;
+
+ }
+
+ if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get()))>=0) {
+
+ accept->get_ok()->set_text(TTR("Makes Sense!"));
+ accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
+ accept->popup_centered_minsize();
+ return false;
+
+ }
+
+ }
+
+ return true;
+}
+
+void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) {
+
+
+ Node *new_parent = scene_root->get_node(p_path);
+ ERR_FAIL_COND(!new_parent);
+
+ //ok all valid
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if (selection.empty())
+ return; //nothing to reparent
+
+ Vector<Node*> nodes;
+
+ for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
+ nodes.push_back(E->get());
+ }
+
+ _do_reparent(new_parent,-1,nodes,p_keep_global_xform);
+
+}
+
+
+void SceneTreeDock::_do_reparent(Node* p_new_parent,int p_position_in_parent,Vector<Node*> p_nodes,bool p_keep_global_xform) {
+
+
+ Node *new_parent = p_new_parent;
+ ERR_FAIL_COND(!new_parent);
+
+ Node *validate=new_parent;
+ while(validate) {
+
+ if (p_nodes.find(validate)!=-1) {
+ ERR_EXPLAIN("Selection changed at some point.. can't reparent");
+ ERR_FAIL();
+ return;
+ }
+ validate=validate->get_parent();
+ }
+
+ //ok all valid
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if (p_nodes.size()==0)
+ return; //nothing to reparent
+
+ //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"));
+
+ List<Pair<NodePath,NodePath> > path_renames;
+ Vector<StringName> former_names;
+
+ int inc=0;
+
+ for(int ni=0;ni<p_nodes.size();ni++) {
+
+ //no undo for now, sorry
+ Node *node = p_nodes[ni];
+
+ fill_path_renames(node,new_parent,&path_renames);
+ former_names.push_back(node->get_name());
+
+ List<Node*> owned;
+ 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--;
+ }
+
+ 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);
+
+ if (p_position_in_parent>=0)
+ editor_data->get_undo_redo().add_do_method(new_parent,"move_child",node,p_position_in_parent+inc);
+
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ String new_name = new_parent->validate_child_name(node);
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_reparent_node",edited_scene->get_path_to(node),edited_scene->get_path_to(new_parent),new_name,-1);
+ editor_data->get_undo_redo().add_undo_method(sed,"live_debug_reparent_node",NodePath(String(edited_scene->get_path_to(new_parent))+"/"+new_name),edited_scene->get_path_to(node->get_parent()),node->get_name(),node->get_index());
+
+ if (p_keep_global_xform) {
+ if (node->cast_to<Node2D>())
+ editor_data->get_undo_redo().add_do_method(node,"set_global_transform",node->cast_to<Node2D>()->get_global_transform());
+ if (node->cast_to<Spatial>())
+ editor_data->get_undo_redo().add_do_method(node,"set_global_transform",node->cast_to<Spatial>()->get_global_transform());
+ if (node->cast_to<Control>())
+ editor_data->get_undo_redo().add_do_method(node,"set_global_pos",node->cast_to<Control>()->get_global_pos());
+ }
+
+ editor_data->get_undo_redo().add_do_method(this,"_set_owners",edited_scene,owners);
+
+ if (AnimationPlayerEditor::singleton->get_key_editor()->get_root()==node)
+ editor_data->get_undo_redo().add_do_method(AnimationPlayerEditor::singleton->get_key_editor(),"set_root",node);
+
+ editor_data->get_undo_redo().add_undo_method(new_parent,"remove_child",node);
+ editor_data->get_undo_redo().add_undo_method(node,"set_name",former_names[ni]);
+
+ inc++;
+
+ }
+
+ //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];
+
+ List<Node*> owned;
+ 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());
+ }
+
+ int child_pos = node->get_position_in_parent();
+
+ 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,child_pos);
+ editor_data->get_undo_redo().add_undo_method(this,"_set_owners",edited_scene,owners);
+ if (AnimationPlayerEditor::singleton->get_key_editor()->get_root()==node)
+ editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::singleton->get_key_editor(),"set_root",node);
+
+ if (p_keep_global_xform) {
+ if (node->cast_to<Node2D>())
+ editor_data->get_undo_redo().add_undo_method(node,"set_transform",node->cast_to<Node2D>()->get_transform());
+ if (node->cast_to<Spatial>())
+ editor_data->get_undo_redo().add_undo_method(node,"set_transform",node->cast_to<Spatial>()->get_transform());
+ if (node->cast_to<Control>())
+ editor_data->get_undo_redo().add_undo_method(node,"set_pos",node->cast_to<Control>()->get_pos());
+ }
+
+
+
+ }
+
+ perform_node_renames(NULL,&path_renames);
+
+ editor_data->get_undo_redo().commit_action();
+ //node->set_owner(owner);
+}
+
+void SceneTreeDock::_script_created(Ref<Script> p_script) {
+
+ Node *selected = scene_tree->get_selected();
+ if (!selected)
+ return;
+ selected->set_script(p_script.get_ref_ptr());
+ editor->push_item(p_script.operator->());
+ button_create_script->hide();
+ button_clear_script->show();
+
+}
+
+
+void SceneTreeDock::_delete_confirm() {
+
+ List<Node*> remove_list = editor_selection->get_selected_node_list();
+
+ if (remove_list.empty())
+ return;
+
+
+ editor->get_editor_plugins_over()->make_visible(false);
+
+ editor_data->get_undo_redo().create_action(TTR("Remove Node(s)"));
+
+ bool entire_scene=false;
+
+ for(List<Node*>::Element *E=remove_list.front();E;E=E->next()) {
+
+ if (E->get()==edited_scene) {
+ entire_scene=true;
+ }
+ }
+
+ if (entire_scene) {
+
+ editor_data->get_undo_redo().add_do_method(editor,"set_edited_scene",(Object*)NULL);
+ editor_data->get_undo_redo().add_undo_method(editor,"set_edited_scene",edited_scene);
+ editor_data->get_undo_redo().add_undo_method(edited_scene,"set_owner",edited_scene->get_owner());
+ editor_data->get_undo_redo().add_undo_reference(edited_scene);
+
+ } else {
+
+ remove_list.sort_custom<Node::Comparator>(); //sort nodes to keep positions
+ List<Pair<NodePath,NodePath> > path_renames;
+
+
+ //delete from animation
+ for(List<Node*>::Element *E=remove_list.front();E;E=E->next()) {
+ Node *n = E->get();
+ if (!n->is_inside_tree() || !n->get_parent())
+ continue;
+
+ fill_path_renames(n,NULL,&path_renames);
+
+ }
+
+ perform_node_renames(NULL,&path_renames);
+ //delete for read
+ for(List<Node*>::Element *E=remove_list.front();E;E=E->next()) {
+ Node *n = E->get();
+ if (!n->is_inside_tree() || !n->get_parent())
+ continue;
+
+ List<Node*> owned;
+ n->get_owned_by(n->get_owner(),&owned);
+ Array owners;
+ for(List<Node*>::Element *E=owned.front();E;E=E->next()) {
+
+ owners.push_back(E->get());
+ }
+
+
+ editor_data->get_undo_redo().add_do_method(n->get_parent(),"remove_child",n);
+ editor_data->get_undo_redo().add_undo_method(n->get_parent(),"add_child",n);
+ editor_data->get_undo_redo().add_undo_method(n->get_parent(),"move_child",n,n->get_index());
+ if (AnimationPlayerEditor::singleton->get_key_editor()->get_root()==n)
+ editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::singleton->get_key_editor(),"set_root",n);
+ editor_data->get_undo_redo().add_undo_method(this,"_set_owners",edited_scene,owners);
+ //editor_data->get_undo_redo().add_undo_method(n,"set_owner",n->get_owner());
+ editor_data->get_undo_redo().add_undo_reference(n);
+
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_remove_and_keep_node",edited_scene->get_path_to(n),n->get_instance_ID());
+ editor_data->get_undo_redo().add_undo_method(sed,"live_debug_restore_node",n->get_instance_ID(),edited_scene->get_path_to(n->get_parent()),n->get_index());
+
+ }
+
+
+ }
+ editor_data->get_undo_redo().commit_action();
+
+
+}
+
+
+
+
+void SceneTreeDock::_selection_changed() {
+
+ int selection_size = EditorNode::get_singleton()->get_editor_selection()->get_selection().size();
+ if (selection_size>1) {
+ //automatically turn on multi-edit
+ _tool_selected(TOOL_MULTI_EDIT);
+ }
+
+ if (selection_size==1) {
+ if(EditorNode::get_singleton()->get_editor_selection()->get_selection().front()->key()->get_script().is_null()) {
+ button_create_script->show();
+ button_clear_script->hide();
+ }
+ else {
+ button_create_script->hide();
+ button_clear_script->show();
+ }
+ } else {
+ button_create_script->hide();
+ button_clear_script->hide();
+ }
+
+ //tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2);
+
+}
+
+
+void SceneTreeDock::_create() {
+
+
+ if (current_option==TOOL_NEW) {
+
+ Node *parent=NULL;
+
+
+ if (edited_scene) {
+ // If root exists in edited scene
+ parent = scene_tree->get_selected();
+ if( !parent )
+ parent = edited_scene;
+
+ } else {
+ // If no root exist in edited scene
+ parent = scene_root;
+ ERR_FAIL_COND(!parent);
+ }
+
+ Object *c = create_dialog->instance_selected();
+
+ ERR_FAIL_COND(!c);
+ Node *child=c->cast_to<Node>();
+ ERR_FAIL_COND(!child);
+
+ editor_data->get_undo_redo().create_action(TTR("Create Node"));
+
+ if (edited_scene) {
+
+ editor_data->get_undo_redo().add_do_method(parent,"add_child",child);
+ editor_data->get_undo_redo().add_do_method(child,"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",child);
+ editor_data->get_undo_redo().add_do_reference(child);
+ editor_data->get_undo_redo().add_undo_method(parent,"remove_child",child);
+
+
+ String new_name = parent->validate_child_name(child);
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_create_node",edited_scene->get_path_to(parent),child->get_class(),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));
+
+ } else {
+
+ editor_data->get_undo_redo().add_do_method(editor,"set_edited_scene",child);
+ editor_data->get_undo_redo().add_do_reference(child);
+ editor_data->get_undo_redo().add_undo_method(editor,"set_edited_scene",(Object*)NULL);
+
+ }
+
+ editor_data->get_undo_redo().commit_action();
+ editor->push_item(c);
+
+ if (c->cast_to<Control>()) {
+ //make editor more comfortable, so some controls don't appear super shrunk
+ Control *ct = c->cast_to<Control>();
+
+ Size2 ms = ct->get_minimum_size();
+ if (ms.width<4)
+ ms.width=40;
+ if (ms.height<4)
+ ms.height=40;
+ ct->set_size(ms);
+ }
+
+
+ } else if (current_option==TOOL_REPLACE) {
+ Node * n = scene_tree->get_selected();
+ ERR_FAIL_COND(!n);
+
+ Object *c = create_dialog->instance_selected();
+
+ ERR_FAIL_COND(!c);
+ Node *newnode=c->cast_to<Node>();
+ ERR_FAIL_COND(!newnode);
+
+ List<PropertyInfo> pinfo;
+ n->get_property_list(&pinfo);
+
+ for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ if (!(E->get().usage&PROPERTY_USAGE_STORAGE))
+ continue;
+ newnode->set(E->get().name,n->get(E->get().name));
+ }
+
+ editor->push_item(NULL);
+
+ //reconnect signals
+ List<MethodInfo> sl;
+
+ n->get_signal_list(&sl);
+ for (List<MethodInfo>::Element *E=sl.front();E;E=E->next()) {
+
+ List<Object::Connection> cl;
+ n->get_signal_connection_list(E->get().name,&cl);
+
+ for(List<Object::Connection>::Element *F=cl.front();F;F=F->next()) {
+
+ Object::Connection &c=F->get();
+ if (!(c.flags&Object::CONNECT_PERSIST))
+ continue;
+ newnode->connect(c.signal,c.target,c.method,varray(),Object::CONNECT_PERSIST);
+ }
+
+ }
+
+ String newname=n->get_name();
+
+ List<Node*> to_erase;
+ for(int i=0;i<n->get_child_count();i++) {
+ if (n->get_child(i)->get_owner()==NULL && n->is_owned_by_parent()) {
+ to_erase.push_back(n->get_child(i));
+ }
+ }
+ n->replace_by(newnode,true);
+
+ if (n==edited_scene) {
+ edited_scene=newnode;
+ editor->set_edited_scene(newnode);
+ newnode->set_editable_instances(n->get_editable_instances());
+ }
+
+ //small hack to make collisionshapes and other kind of nodes to work
+ for(int i=0;i<newnode->get_child_count();i++) {
+ Node *c=newnode->get_child(i);
+ c->call("set_transform", c->call("get_transform") );
+ }
+ editor_data->get_undo_redo().clear_history();
+ newnode->set_name(newname);
+
+ editor->push_item(newnode);
+
+ memdelete(n);
+
+ while(to_erase.front()) {
+ memdelete(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+
+
+ }
+
+}
+
+
+void SceneTreeDock::set_edited_scene(Node* p_scene) {
+
+ edited_scene=p_scene;
+}
+
+void SceneTreeDock::set_selected(Node *p_node, bool p_emit_selected ) {
+
+ scene_tree->set_selected(p_node,p_emit_selected);
+
+}
+
+void SceneTreeDock::import_subscene() {
+
+ import_subscene_dialog->popup_centered_ratio();
+}
+
+void SceneTreeDock::_import_subscene() {
+
+ Node* parent = scene_tree->get_selected();
+ if (!parent) {
+ parent = editor_data->get_edited_scene_root();
+ ERR_FAIL_COND(!parent);
+ }
+
+ import_subscene_dialog->move(parent,edited_scene);
+ editor_data->get_undo_redo().clear_history(); //no undo for now..
+
+
+/*
+ editor_data->get_undo_redo().create_action("Import Subscene");
+ editor_data->get_undo_redo().add_do_method(parent,"add_child",ss);
+ //editor_data->get_undo_redo().add_do_method(editor_selection,"clear");
+ //editor_data->get_undo_redo().add_do_method(editor_selection,"add_node",child);
+ editor_data->get_undo_redo().add_do_reference(ss);
+ editor_data->get_undo_redo().add_undo_method(parent,"remove_child",ss);
+ editor_data->get_undo_redo().commit_action();
+*/
+}
+
+void SceneTreeDock::_new_scene_from(String p_file) {
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if (selection.size()!=1) {
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("This operation requires a single selected node."));
+ accept->popup_centered_minsize();
+ return;
+ }
+
+ Node *base = selection.front()->get();
+
+ Map<Node*,Node*> reown;
+ reown[editor_data->get_edited_scene_root()]=base;
+ Node *copy = base->duplicate_and_reown(reown);
+ if (copy) {
+
+ Ref<PackedScene> sdata = memnew( PackedScene );
+ Error err = sdata->pack(copy);
+ memdelete(copy);
+
+ if (err!=OK) {
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied."));
+ accept->popup_centered_minsize();
+ return;
+ }
+
+ int flg=0;
+ if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources"))
+ flg|=ResourceSaver::FLAG_COMPRESS;
+ /*
+ if (EditorSettings::get_singleton()->get("filesystem/on_save/save_paths_as_relative"))
+ flg|=ResourceSaver::FLAG_RELATIVE_PATHS;
+ */
+
+
+ err = ResourceSaver::save(p_file,sdata,flg);
+ if (err!=OK) {
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("Error saving scene."));
+ accept->popup_centered_minsize();
+ return;
+ }
+ _replace_with_branch_scene(p_file, base);
+ } else {
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("Error duplicating scene to save it."));
+ accept->popup_centered_minsize();
+ return;
+ }
+
+}
+
+static bool _is_node_visible(Node* p_node) {
+
+ if (!p_node->get_owner())
+ return false;
+ if (p_node->get_owner()!=EditorNode::get_singleton()->get_edited_scene() && !EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node->get_owner()))
+ return false;
+
+ return true;
+
+}
+
+static bool _has_visible_children(Node* p_node) {
+
+ bool collapsed = p_node->is_displayed_folded();
+ if (collapsed)
+ return false;
+
+ for(int i=0;i<p_node->get_child_count();i++) {
+
+ Node* child = p_node->get_child(i);
+ if (!_is_node_visible(child))
+ continue;
+
+ return true;
+ }
+
+ return false;
+
+}
+
+
+
+static Node* _find_last_visible(Node* p_node) {
+
+ Node* last=NULL;
+
+ bool collapsed = p_node->is_displayed_folded();
+
+ if (!collapsed) {
+ for(int i=0;i<p_node->get_child_count();i++) {
+ if (_is_node_visible(p_node->get_child(i))) {
+ last=p_node->get_child(i);
+ }
+ }
+ }
+
+ if (last) {
+ Node* lastc=_find_last_visible(last);
+ if (lastc)
+ last=lastc;
+
+
+ } else {
+ last=p_node;
+ }
+
+ return last;
+}
+
+
+void SceneTreeDock::_normalize_drop(Node*& to_node, int &to_pos, int p_type) {
+
+ to_pos=-1;
+
+ if (p_type==-1) {
+ //drop at above selected node
+ if (to_node==EditorNode::get_singleton()->get_edited_scene()) {
+ to_node=NULL;
+ ERR_EXPLAIN("Cannot perform drop above the root node!");
+ ERR_FAIL();
+ }
+
+ to_pos=to_node->get_index();
+ to_node=to_node->get_parent();
+
+ } else if (p_type==1) {
+ //drop at below selected node
+ if (to_node==EditorNode::get_singleton()->get_edited_scene()) {
+ //if at lower sibling of root node
+ to_pos=0; //just insert at begining of root node
+ return;
+ }
+
+
+ Node* lower_sibling=NULL;
+
+
+
+ if (_has_visible_children(to_node) ) {
+ to_pos=0;
+ } else {
+
+
+ for(int i=to_node->get_index()+1;i<to_node->get_parent()->get_child_count();i++) {
+ Node *c =to_node->get_parent()->get_child(i);
+ if (_is_node_visible(c)) {
+ lower_sibling=c;
+ break;
+ }
+ }
+ if (lower_sibling) {
+ to_pos=lower_sibling->get_index();
+ }
+
+ to_node=to_node->get_parent();
+
+
+ }
+#if 0
+ //quite complicated, look for next visible in tree
+ upper_sibling=_find_last_visible(upper_sibling);
+
+ if (upper_sibling->get_parent()==to_node->get_parent()) {
+ //just insert over this node because nothing is above at an upper level
+ to_pos=to_node->get_index();
+ to_node=to_node->get_parent();
+ } else {
+ to_pos=-1; //insert last in whathever is up
+ to_node=upper_sibling->get_parent(); //insert at a parent of whathever is up
+ }
+
+
+ } else {
+ //just insert over this node because nothing is above at the same level
+ to_pos=to_node->get_index();
+ to_node=to_node->get_parent();
+ }
+#endif
+
+ }
+
+}
+
+void SceneTreeDock::_files_dropped(Vector<String> p_files,NodePath p_to,int p_type) {
+
+ Node *node = get_node(p_to);
+ ERR_FAIL_COND(!node);
+
+ int to_pos=-1;
+ _normalize_drop(node,to_pos,p_type);
+ _perform_instance_scenes(p_files,node,to_pos);
+}
+
+void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
+ Ref<Script> scr = ResourceLoader::load(p_file);
+ ERR_FAIL_COND(!scr.is_valid());
+ Node *n = get_node(p_to);
+ if (n) {
+ n->set_script(scr.get_ref_ptr());
+ }
+}
+
+void SceneTreeDock::_nodes_dragged(Array p_nodes,NodePath p_to,int p_type) {
+
+ Vector<Node*> nodes;
+ Node *to_node;
+
+ for(int i=0;i<p_nodes.size();i++) {
+ Node *n=get_node((p_nodes[i]));
+ if (n) {
+ nodes.push_back(n);
+ }
+ }
+
+ if (nodes.size()==0)
+ return;
+
+ to_node=get_node(p_to);
+ if (!to_node)
+ return;
+
+ int to_pos=-1;
+
+ _normalize_drop(to_node,to_pos,p_type);
+ _do_reparent(to_node,to_pos,nodes,true);
+
+}
+
+void SceneTreeDock::_tree_rmb(const Vector2& p_menu_pos) {
+ if (!EditorNode::get_singleton()->get_edited_scene()) {
+
+ menu->clear();
+ menu->add_icon_shortcut(get_icon("Add","EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
+ menu->add_icon_shortcut(get_icon("Instance","EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE);
+
+ menu->set_size(Size2(1,1));
+ menu->set_pos(p_menu_pos);
+ menu->popup();
+ return;
+ }
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if (selection.size()==0)
+ return;
+
+ menu->clear();
+
+
+ if (selection.size()==1) {
+ menu->add_icon_shortcut(get_icon("Add","EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW);
+ menu->add_icon_shortcut(get_icon("Instance","EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE);
+ menu->add_separator();
+ menu->add_icon_shortcut(get_icon("Reload","EditorIcons"),ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE);
+ //menu->add_separator(); moved to their own dock
+ //menu->add_icon_item(get_icon("Groups","EditorIcons"),TTR("Edit Groups"),TOOL_GROUP);
+ //menu->add_icon_item(get_icon("Connect","EditorIcons"),TTR("Edit Connections"),TOOL_CONNECT);
+ menu->add_separator();
+ menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT);
+ menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT);
+ menu->add_separator();
+ }
+
+ menu->add_icon_shortcut(get_icon("Up","EditorIcons"),ED_GET_SHORTCUT("scene_tree/move_up"), TOOL_MOVE_UP);
+ menu->add_icon_shortcut(get_icon("Down","EditorIcons"),ED_GET_SHORTCUT("scene_tree/move_down"), TOOL_MOVE_DOWN);
+ 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);
+
+ if (selection.size()==1) {
+ 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);
+ 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_separator();
+ menu->add_icon_shortcut(get_icon("Remove","EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE);
+ menu->set_size(Size2(1,1));
+ menu->set_pos(p_menu_pos);
+ menu->popup();
+
+}
+
+
+void SceneTreeDock::_filter_changed(const String& p_filter) {
+
+ scene_tree->set_filter(p_filter);
+}
+
+String SceneTreeDock::get_filter() {
+
+ return filter->get_text();
+}
+
+void SceneTreeDock::set_filter(const String& p_filter){
+
+ filter->set_text(p_filter);
+ scene_tree->set_filter(p_filter);
+}
+
+
+void SceneTreeDock::_focus_node() {
+
+ Node *node = scene_tree->get_selected();
+ ERR_FAIL_COND(!node);
+
+ if (node->is_class("CanvasItem")) {
+ CanvasItemEditorPlugin *editor = editor_data->get_editor("2D")->cast_to<CanvasItemEditorPlugin>();
+ editor->get_canvas_item_editor()->focus_selection();
+ } else {
+ SpatialEditorPlugin *editor = editor_data->get_editor("3D")->cast_to<SpatialEditorPlugin>();
+ editor->get_spatial_editor()->get_editor_viewport(0)->focus_selection();
+ }
+}
+
+void SceneTreeDock::open_script_dialog(Node* p_for_node) {
+
+ scene_tree->set_selected(p_for_node,false);
+ _tool_selected(TOOL_ATTACH_SCRIPT);
+}
+
+void SceneTreeDock::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_tool_selected"),&SceneTreeDock::_tool_selected,DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("_create"),&SceneTreeDock::_create);
+ //ClassDB::bind_method(D_METHOD("_script_created"),&SceneTreeDock::_script_created);
+ ClassDB::bind_method(D_METHOD("_node_reparent"),&SceneTreeDock::_node_reparent);
+ ClassDB::bind_method(D_METHOD("_set_owners"),&SceneTreeDock::_set_owners);
+ ClassDB::bind_method(D_METHOD("_node_selected"),&SceneTreeDock::_node_selected);
+ ClassDB::bind_method(D_METHOD("_node_renamed"),&SceneTreeDock::_node_renamed);
+ ClassDB::bind_method(D_METHOD("_script_created"),&SceneTreeDock::_script_created);
+ ClassDB::bind_method(D_METHOD("_load_request"),&SceneTreeDock::_load_request);
+ ClassDB::bind_method(D_METHOD("_script_open_request"),&SceneTreeDock::_script_open_request);
+ ClassDB::bind_method(D_METHOD("_unhandled_key_input"),&SceneTreeDock::_unhandled_key_input);
+ ClassDB::bind_method(D_METHOD("_input"),&SceneTreeDock::_input);
+ 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("_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);
+ ClassDB::bind_method(D_METHOD("_new_scene_from"),&SceneTreeDock::_new_scene_from);
+ ClassDB::bind_method(D_METHOD("_nodes_dragged"),&SceneTreeDock::_nodes_dragged);
+ ClassDB::bind_method(D_METHOD("_files_dropped"),&SceneTreeDock::_files_dropped);
+ ClassDB::bind_method(D_METHOD("_script_dropped"),&SceneTreeDock::_script_dropped);
+ ClassDB::bind_method(D_METHOD("_tree_rmb"),&SceneTreeDock::_tree_rmb);
+ ClassDB::bind_method(D_METHOD("_filter_changed"),&SceneTreeDock::_filter_changed);
+ ClassDB::bind_method(D_METHOD("_focus_node"),&SceneTreeDock::_focus_node);
+
+
+ ClassDB::bind_method(D_METHOD("instance"),&SceneTreeDock::instance);
+}
+
+
+
+SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelection *p_editor_selection,EditorData &p_editor_data) {
+
+ editor=p_editor;
+ edited_scene=NULL;
+ editor_data=&p_editor_data;
+ editor_selection=p_editor_selection;
+ scene_root=p_scene_root;
+
+ VBoxContainer *vbc = this;
+
+ HBoxContainer *filter_hbc = memnew( HBoxContainer );
+ ToolButton *tb;
+
+ ED_SHORTCUT("scene_tree/add_child_node",TTR("Add Child Node"), KEY_MASK_CMD|KEY_A);
+ ED_SHORTCUT("scene_tree/instance_scene",TTR("Instance Child Scene"));
+ ED_SHORTCUT("scene_tree/change_node_type", TTR("Change Type"));
+ ED_SHORTCUT("scene_tree/attach_script", TTR("Attach Script"));
+ ED_SHORTCUT("scene_tree/clear_script", TTR("Clear Script"));
+ ED_SHORTCUT("scene_tree/move_up", TTR("Move Up"), KEY_MASK_CMD | KEY_UP);
+ ED_SHORTCUT("scene_tree/move_down", TTR("Move Down"), KEY_MASK_CMD | KEY_DOWN);
+ ED_SHORTCUT("scene_tree/duplicate", TTR("Duplicate"),KEY_MASK_CMD | KEY_D);
+ ED_SHORTCUT("scene_tree/reparent", TTR("Reparent"));
+ ED_SHORTCUT("scene_tree/merge_from_scene", TTR("Merge From Scene"));
+ ED_SHORTCUT("scene_tree/save_branch_as_scene", TTR("Save Branch as Scene"));
+ ED_SHORTCUT("scene_tree/copy_node_path", TTR("Copy Node Path"), KEY_MASK_CMD|KEY_C);
+ ED_SHORTCUT("scene_tree/delete_no_confirm", TTR("Delete (No Confirm)"), KEY_MASK_SHIFT|KEY_DELETE);
+ ED_SHORTCUT("scene_tree/delete", TTR("Delete"), KEY_DELETE);
+
+ tb = memnew( ToolButton );
+ tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_NEW, false));
+ tb->set_tooltip(TTR("Add/Create a New Node"));
+ tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node"));
+ filter_hbc->add_child(tb);
+ button_add=tb;
+
+ tb = memnew( ToolButton );
+ tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_INSTANCE, false));
+ tb->set_tooltip(TTR("Instance a scene file as a Node. Creates an inherited scene if no root node exists."));
+ tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene"));
+ filter_hbc->add_child(tb);
+ button_instance=tb;
+
+
+
+ vbc->add_child(filter_hbc);
+ filter = memnew( LineEdit );
+ filter->set_h_size_flags(SIZE_EXPAND_FILL);
+ filter_hbc->add_child(filter);
+ filter_icon = memnew( TextureRect );
+ filter_hbc->add_child(filter_icon);
+ filter_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ filter->connect("text_changed",this,"_filter_changed");
+
+
+ tb = memnew( ToolButton );
+ tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_ATTACH_SCRIPT, false));
+ tb->set_tooltip(TTR("Attach a new or existing script for the selected node."));
+ tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script"));
+ filter_hbc->add_child(tb);
+ button_create_script=tb;
+
+ tb = memnew(ToolButton);
+ tb->connect("pressed", this, "_tool_selected", make_binds(TOOL_CLEAR_SCRIPT, false));
+ tb->set_tooltip(TTR("Clear a script for the selected node."));
+ tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/clear_script"));
+ filter_hbc->add_child(tb);
+ button_clear_script = tb;
+
+
+ scene_tree = memnew( SceneTreeEditor(false,true,true ));
+ vbc->add_child(scene_tree);
+ scene_tree->set_v_size_flags(SIZE_EXPAND|SIZE_FILL);
+ scene_tree->connect("rmb_pressed",this,"_tree_rmb");
+
+ scene_tree->connect("node_selected", this,"_node_selected",varray(),CONNECT_DEFERRED);
+ scene_tree->connect("node_renamed", this,"_node_renamed",varray(),CONNECT_DEFERRED);
+ scene_tree->connect("node_prerename", this,"_node_prerenamed");
+ scene_tree->connect("open",this,"_load_request");
+ scene_tree->connect("open_script",this,"_script_open_request");
+ scene_tree->connect("nodes_rearranged",this,"_nodes_dragged");
+ scene_tree->connect("files_dropped",this,"_files_dropped");
+ scene_tree->connect("script_dropped",this,"_script_dropped");
+ scene_tree->connect("nodes_dragged",this,"_nodes_drag_begin");
+
+ scene_tree->get_scene_tree()->connect("item_double_clicked", this, "_focus_node");
+
+ scene_tree->set_undo_redo(&editor_data->get_undo_redo());
+ scene_tree->set_editor_selection(editor_selection);
+
+
+ create_dialog = memnew( CreateDialog );
+ create_dialog->set_base_type("Node");
+ add_child(create_dialog);
+ create_dialog->connect("create",this,"_create");
+
+ //groups_editor = memnew( GroupsEditor );
+ //add_child(groups_editor);
+ //groups_editor->set_undo_redo(&editor_data->get_undo_redo());
+
+ //connect_dialog = memnew( ConnectionsDialog(p_editor) );
+ //add_child(connect_dialog);
+ //connect_dialog->set_undoredo(&editor_data->get_undo_redo());
+
+ script_create_dialog = memnew( ScriptCreateDialog );
+ add_child(script_create_dialog);
+ script_create_dialog->connect("script_created",this,"_script_created");
+
+ reparent_dialog = memnew( ReparentDialog );
+ add_child(reparent_dialog);
+ reparent_dialog->connect("reparent",this,"_node_reparent");
+
+ accept = memnew( AcceptDialog );
+ add_child(accept);
+
+ file = memnew( EditorFileDialog );
+ add_child(file);
+ file->connect("file_selected",this,"instance");
+ set_process_unhandled_key_input(true);
+
+ delete_dialog = memnew( ConfirmationDialog );
+ add_child(delete_dialog);
+ delete_dialog->connect("confirmed",this,"_delete_confirm");
+
+ import_subscene_dialog = memnew( EditorSubScene );
+ add_child(import_subscene_dialog);
+ import_subscene_dialog->connect("subscene_selected",this,"_import_subscene");
+
+ new_scene_from_dialog = memnew( EditorFileDialog );
+ new_scene_from_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ add_child(new_scene_from_dialog);
+ new_scene_from_dialog->connect("file_selected",this,"_new_scene_from");
+
+
+ menu = memnew( PopupMenu );
+ add_child(menu);
+ menu->connect("id_pressed",this,"_tool_selected");
+ first_enter=true;
+ restore_script_editor_on_drag=false;
+
+ vbc->add_constant_override("separation",4);
+ set_process_input(true);
+}