From 0c57a58056d68e0e859ab8fd91676143cec9ef17 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Wed, 11 May 2016 20:57:52 -0300 Subject: [PATCH] ability to drag scenes from filesystem to tree for instancing --- modules/gdscript/gd_functions.cpp | 2 +- scene/gui/tree.cpp | 2 + tools/editor/editor_node.cpp | 5 +- tools/editor/editor_node.h | 2 +- tools/editor/scene_tree_dock.cpp | 179 ++++++++++++++++++++--------- tools/editor/scene_tree_dock.h | 6 +- tools/editor/scene_tree_editor.cpp | 54 +++++++-- tools/editor/scenes_dock.cpp | 2 +- 8 files changed, 181 insertions(+), 71 deletions(-) diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp index 9b7d8eeac4a..96fb9d81a74 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -1046,7 +1046,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va } break; case FUNC_MAX: { - ERR_FAIL_V(); + ERR_FAIL(); } break; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index c141635bbf7..062a377cee4 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3440,6 +3440,8 @@ void Tree::set_value_evaluator(ValueEvaluator *p_evaluator) { } void Tree::set_drop_mode_flags(int p_flags) { + if (drop_mode_flags==p_flags) + return; drop_mode_flags=p_flags; if (drop_mode_flags==0) { drop_mode_over=NULL; diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 8e5087b4057..c9cec3b7f43 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -3739,10 +3739,9 @@ void EditorNode::open_request(const String& p_path) { //_menu_option_confirm(FILE_EXTERNAL_OPEN_SCENE,false); } +void EditorNode::request_instance_scene(const String &p_path) { -Node* EditorNode::request_instance_scene(const String &p_path) { - - return scene_tree_dock->instance(p_path); + scene_tree_dock->instance(p_path); } diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index b3faa21cf3c..cfec15c3833 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -644,7 +644,7 @@ public: static VSplitContainer *get_top_split() { return singleton->top_split; } - Node* request_instance_scene(const String &p_path); + void request_instance_scene(const String &p_path); ScenesDock *get_scenes_dock(); static UndoRedo* get_undo_redo() { return &singleton->editor_data.get_undo_redo(); } diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index 252e7c890c8..ce7a0b29112 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -59,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) { @@ -69,61 +69,107 @@ 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); - Node*instanced_scene=NULL; - Ref sdata = ResourceLoader::load(p_file); - if (sdata.is_valid()) - instanced_scene=sdata->instance(true); + Vector scenes; + scenes.push_back(p_file); + instance_scenes(scenes,parent,-1); + +} + +void SceneTreeDock::instance_scenes(const Vector& 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; - } + ERR_FAIL_COND(!parent); - // If the scene hasn't been saved yet a cyclical dependency cannot exist. - if (edited_scene->get_filename()!="") { - if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) { + Vector instances; - 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.")); + 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(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;igenerate_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;ivalidate_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().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; - } bool SceneTreeDock::_cyclical_dependency_exists(const String& p_target_scene_path, Node* p_desired_node) { @@ -1510,32 +1556,20 @@ static Node* _find_last_visible(Node*p_node) { return last; } -void SceneTreeDock::_nodes_dragged(Array p_nodes,NodePath p_to,int p_type) { - Vector nodes; - Node *to_node; +void SceneTreeDock::_normalize_drop(Node*& to_node, int &to_pos,int p_type) { - for(int i=0;iget_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 - ERR_FAIL_COND(to_node==EditorNode::get_singleton()->get_edited_scene()); + 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;iget_index();i++) { @@ -1568,7 +1602,10 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes,NodePath p_to,int p_type) { } else if (p_type==1) { //drop at below selected node - ERR_FAIL_COND(to_node==EditorNode::get_singleton()->get_edited_scene()); + 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; @@ -1608,6 +1645,38 @@ void SceneTreeDock::_nodes_dragged(Array p_nodes,NodePath p_to,int p_type) { } +} + +void SceneTreeDock::_files_dropped(Vector 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 nodes; + Node *to_node; + + for(int i=0;iconnect("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); diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h index 264a05e23e6..5dc1e3e12e7 100644 --- a/tools/editor/scene_tree_dock.h +++ b/tools/editor/scene_tree_dock.h @@ -130,7 +130,10 @@ class SceneTreeDock : public VBoxContainer { void _fill_path_renames(Vector base_path,Vector new_base_path,Node * p_node, List > *p_renames); + void _normalize_drop(Node*& to_node, int &to_pos,int p_type); + void _nodes_dragged(Array p_nodes,NodePath p_to,int p_type); + void _files_dropped(Vector p_files,NodePath p_to,int p_type); protected: @@ -140,7 +143,8 @@ public: void import_subscene(); void set_edited_scene(Node* p_scene); - Node* instance(const String& p_path); + void instance(const String& p_path); + void instance_scenes(const Vector& p_files,Node* parent,int p_pos); void set_selected(Node *p_node, bool p_emit_selected=false); void fill_path_renames(Node* p_node, Node *p_new_parent, List > *p_renames); void perform_node_renames(Node* p_base,List > *p_renames, Map, Set > *r_rem_anims=NULL); diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp index 720516bd7e6..fd79460aa89 100644 --- a/tools/editor/scene_tree_editor.cpp +++ b/tools/editor/scene_tree_editor.cpp @@ -839,16 +839,43 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_da return false; //not editable tree Dictionary d=p_data; - if (!d.has("type") || String(d["type"])!="nodes") - return false; - TreeItem *item = tree->get_item_at_pos(p_point); - if (!item) - return false; - int section = tree->get_drop_section_at_pos(p_point); - if (section<-1 || (section==-1 && !item->get_parent())) + if (!d.has("type")) return false; - return true; + if (String(d["type"])=="files") { + + Vector files = d["files"]; + + if (files.size()==0) + return false; //weird + + + for(int i=0;iget_file_type(file); + if (ftype!="PackedScene") + return false; + } + + tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN|Tree::DROP_MODE_ON_ITEM); //so it works.. + + return true; + } + + + if (String(d["type"])=="nodes") { + TreeItem *item = tree->get_item_at_pos(p_point); + if (!item) + return false; + int section = tree->get_drop_section_at_pos(p_point); + if (section<-1 || (section==-1 && !item->get_parent())) + return false; + + return true; + + } + + return false; } void SceneTreeEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) { @@ -869,9 +896,15 @@ void SceneTreeEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,C Dictionary d=p_data; - Array nodes=d["nodes"]; + if (String(d["type"])=="nodes") { + Array nodes=d["nodes"]; + emit_signal("nodes_rearranged",nodes,np,section); + } - emit_signal("nodes_rearranged",nodes,np,section); + if (String(d["type"])=="files") { + + emit_signal("files_dropped",d["files"],np,section); + } } @@ -903,6 +936,7 @@ void SceneTreeEditor::_bind_methods() { ADD_SIGNAL( MethodInfo("node_prerename") ); ADD_SIGNAL( MethodInfo("node_changed") ); ADD_SIGNAL( MethodInfo("nodes_rearranged",PropertyInfo(Variant::ARRAY,"paths"),PropertyInfo(Variant::NODE_PATH,"to_path"),PropertyInfo(Variant::INT,"type") ) ); + ADD_SIGNAL( MethodInfo("files_dropped",PropertyInfo(Variant::STRING_ARRAY,"files"),PropertyInfo(Variant::NODE_PATH,"to_path"),PropertyInfo(Variant::INT,"type") ) ); ADD_SIGNAL( MethodInfo("open") ); ADD_SIGNAL( MethodInfo("open_script") ); diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp index f44435d9b3e..c03142a3e71 100644 --- a/tools/editor/scenes_dock.cpp +++ b/tools/editor/scenes_dock.cpp @@ -1131,7 +1131,7 @@ bool ScenesDock::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Co Dictionary drag_data = p_data; - print_line("CAN IT DROP DATA?"); + if (drag_data.has("type") && String(drag_data["type"])=="resource") { return true; }