ソースを参照

ability to drag scenes from filesystem to tree for instancing

Juan Linietsky 9 年 前
コミット
0c57a58056

+ 1 - 1
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;
 
 	}

+ 2 - 0
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;

+ 2 - 3
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);
 
 }
 

+ 1 - 1
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(); }
 

+ 125 - 54
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,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);
 
-	Node*instanced_scene=NULL;
-	Ref<PackedScene> sdata = ResourceLoader::load(p_file);
-	if (sdata.is_valid())
-		instanced_scene=sdata->instance(true);
+	Vector<String> scenes;
+	scenes.push_back(p_file);
+	instance_scenes(scenes,parent,-1);
 
+}
 
-	if (!instanced_scene) {
+void SceneTreeDock::instance_scenes(const Vector<String>& p_files,Node* parent,int p_pos) {
 
-		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()!="") {
 
-		if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) {
+	ERR_FAIL_COND(!parent);
 
-			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;
 
 }
 
@@ -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<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;
+void SceneTreeDock::_normalize_drop(Node*& to_node, int &to_pos,int p_type) {
 
-	to_node=get_node(p_to);
-	if (!to_node)
-		return;
-
-
-	int to_pos=-1;
+	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
-		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;i<to_node->get_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<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);
 
 }
@@ -1631,6 +1700,7 @@ void SceneTreeDock::_bind_methods() {
 	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);
@@ -1702,6 +1772,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
 	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);

+ 5 - 1
tools/editor/scene_tree_dock.h

@@ -130,7 +130,10 @@ class SceneTreeDock : public VBoxContainer {
 
 	void _fill_path_renames(Vector<StringName> base_path,Vector<StringName> new_base_path,Node * p_node, List<Pair<NodePath,NodePath> > *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<String> 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<String>& 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<Pair<NodePath,NodePath> > *p_renames);
 	void perform_node_renames(Node* p_base,List<Pair<NodePath,NodePath> > *p_renames, Map<Ref<Animation>, Set<int> > *r_rem_anims=NULL);

+ 44 - 10
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<String> files = d["files"];
+
+		if (files.size()==0)
+			return false; //weird
+
+
+		for(int i=0;i<files.size();i++) {
+			String file = files[0];
+			String ftype = EditorFileSystem::get_singleton()->get_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") );

+ 1 - 1
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;
 	}