summaryrefslogtreecommitdiff
path: root/tools/editor/scene_tree_dock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/editor/scene_tree_dock.cpp')
-rw-r--r--tools/editor/scene_tree_dock.cpp350
1 files changed, 304 insertions, 46 deletions
diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp
index 113d18ea73..ce7a0b2911 100644
--- a/tools/editor/scene_tree_dock.cpp
+++ b/tools/editor/scene_tree_dock.cpp
@@ -40,6 +40,9 @@
#include "tools/editor/plugins/animation_player_editor_plugin.h"
#include "animation_editor.h"
+
+
+
void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
uint32_t sc = p_event.key.get_scancode_with_modifiers();
@@ -56,7 +59,7 @@ void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
}
}
-Node* SceneTreeDock::instance(const String& p_file) {
+void SceneTreeDock::instance(const String& p_file) {
Node *parent = scene_tree->get_selected();
if (!parent || !edited_scene) {
@@ -66,60 +69,106 @@ Node* SceneTreeDock::instance(const String& p_file) {
accept->get_ok()->set_text(TTR("Ok :( "));
accept->set_text(TTR("No parent to instance a child at."));
accept->popup_centered_minsize();
- return NULL;
+ return;
};
- ERR_FAIL_COND_V(!parent,NULL);
+ ERR_FAIL_COND(!parent);
+
+ Vector<String> scenes;
+ scenes.push_back(p_file);
+ instance_scenes(scenes,parent,-1);
- Node*instanced_scene=NULL;
- Ref<PackedScene> sdata = ResourceLoader::load(p_file);
- if (sdata.is_valid())
- instanced_scene=sdata->instance(true);
+}
+void SceneTreeDock::instance_scenes(const Vector<String>& p_files,Node* parent,int p_pos) {
- if (!instanced_scene) {
- current_option=-1;
- //accept->get_cancel()->hide();
- accept->get_ok()->set_text(TTR("Ugh"));
- accept->set_text(String(TTR("Error loading scene from "))+p_file);
- accept->popup_centered_minsize();
- return NULL;
- }
- // If the scene hasn't been saved yet a cyclical dependency cannot exist.
- if (edited_scene->get_filename()!="") {
+ ERR_FAIL_COND(!parent);
- if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) {
- accept->get_ok()->set_text(TTR("Ok"));
- accept->set_text(String(TTR("Cannot instance the scene '"))+p_file+String("' because the current scene exists within one of its' nodes."));
+ 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(String(TTR("Error loading scene from "))+p_files[i]);
accept->popup_centered_minsize();
- return NULL;
+ 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(String(TTR("Error instancing scene from "))+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(String(TTR("Cannot instance the scene '"))+p_files[i]+String(TTR("' because the current scene exists within one of its' nodes.")));
+ 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;i<instances.size();i++) {
+ memdelete(instances[i]);
+ }
+ return;
+ }
+
+
+
//instanced_scene->generate_instance_state();
- instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
- editor_data->get_undo_redo().create_action(TTR("Instance Scene"));
- editor_data->get_undo_redo().add_do_method(parent,"add_child",instanced_scene);
- 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);
+ editor_data->get_undo_redo().create_action(TTR("Instance Scene(s)"));
+ for(int i=0;i<instances.size();i++) {
- 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_file,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));
+ Node* instanced_scene=instances[i];
- editor_data->get_undo_redo().commit_action();
+ 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->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();
- return instanced_scene;
}
@@ -943,16 +992,37 @@ bool SceneTreeDock::_validate_no_foreign() {
void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) {
- Node *node = scene_tree->get_selected();
- ERR_FAIL_COND(!node);
- ERR_FAIL_COND(node==edited_scene);
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 (editor_selection->is_selected(validate)) {
+ if (p_nodes.find(validate)!=-1) {
ERR_EXPLAIN("Selection changed at some point.. can't reparent");
ERR_FAIL();
return;
@@ -964,20 +1034,20 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) {
List<Node*> selection = editor_selection->get_selected_node_list();
- if (selection.empty())
+ if (p_nodes.size()==0)
return; //nothing to reparent
//sort by tree order, so re-adding is easy
- selection.sort_custom<Node::Comparator>();
+ p_nodes.sort_custom<Node::Comparator>();
editor_data->get_undo_redo().create_action(TTR("Reparent Node"));
List<Pair<NodePath,NodePath> > path_renames;
- for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
+ for(int ni=0;ni<p_nodes.size();ni++) {
//no undo for now, sorry
- Node *node = E->get();
+ Node *node = p_nodes[ni];
fill_path_renames(node,new_parent,&path_renames);
@@ -994,6 +1064,9 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) {
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+ni);
+
ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
String new_name = new_parent->validate_child_name(node->get_name());
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);
@@ -1030,9 +1103,9 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) {
- for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
+ for(int ni=0;ni<p_nodes.size();ni++) {
- Node *node = E->get();
+ Node *node = p_nodes[ni];
List<Node*> owned;
node->get_owned_by(node->get_owner(),&owned);
@@ -1078,7 +1151,6 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) {
//node->set_owner(owner);
}
-
void SceneTreeDock::_script_created(Ref<Script> p_script) {
Node *selected = scene_tree->get_selected();
@@ -1431,6 +1503,184 @@ void SceneTreeDock::_new_scene_from(String p_file) {
}
+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->has_meta("_editor_collapsed") ? (bool)p_node->get_meta("_editor_collapsed") : false;
+ 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(p_node))
+ continue;
+
+ return true;
+ }
+
+ return false;
+
+}
+
+
+static Node* _find_last_visible(Node*p_node) {
+
+ Node*last=NULL;
+ 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 && 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
+ } else if (p_type==-1) {
+ //drop at above selected node
+ if (to_node==EditorNode::get_singleton()->get_edited_scene()) {
+ to_node=NULL;
+ ERR_FAIL_COND(to_node==EditorNode::get_singleton()->get_edited_scene());
+ }
+ Node* upper_sibling=NULL;
+
+ for(int i=0;i<to_node->get_index();i++) {
+ Node *c =to_node->get_parent()->get_child(i);
+ if (_is_node_visible(c)) {
+ upper_sibling=c;
+ }
+ }
+
+
+ if (upper_sibling) {
+ //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();
+ }
+
+ } else if (p_type==1) {
+ //drop at below selected node
+ if (to_node==EditorNode::get_singleton()->get_edited_scene()) {
+ to_node=NULL;
+ ERR_FAIL_COND(to_node==EditorNode::get_singleton()->get_edited_scene());
+ }
+
+
+ Node* lower_sibling=NULL;
+
+ 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;
+ }
+ }
+
+ 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);
+ instance_scenes(p_files,node,to_pos);
+}
+
+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]));
+ 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::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_tool_selected"),&SceneTreeDock::_tool_selected);
@@ -1449,6 +1699,9 @@ void SceneTreeDock::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_import_subscene"),&SceneTreeDock::_import_subscene);
ObjectTypeDB::bind_method(_MD("_selection_changed"),&SceneTreeDock::_selection_changed);
ObjectTypeDB::bind_method(_MD("_new_scene_from"),&SceneTreeDock::_new_scene_from);
+ ObjectTypeDB::bind_method(_MD("_nodes_dragged"),&SceneTreeDock::_nodes_dragged);
+ ObjectTypeDB::bind_method(_MD("_files_dropped"),&SceneTreeDock::_files_dropped);
+
ObjectTypeDB::bind_method(_MD("instance"),&SceneTreeDock::instance);
}
@@ -1518,6 +1771,9 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
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->set_undo_redo(&editor_data->get_undo_redo());
scene_tree->set_editor_selection(editor_selection);
@@ -1612,6 +1868,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
add_child(new_scene_from_dialog);
new_scene_from_dialog->connect("file_selected",this,"_new_scene_from");
+
+
first_enter=true;