summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/doc/doc_data.cpp2
-rw-r--r--tools/editor/editor_node.cpp131
-rw-r--r--tools/editor/editor_node.h12
-rw-r--r--tools/editor/editor_settings.cpp6
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.cpp32
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.h4
-rw-r--r--tools/editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/script_editor_plugin.cpp4
-rw-r--r--tools/editor/plugins/shader_editor_plugin.cpp6
-rw-r--r--tools/editor/project_export.cpp11
-rw-r--r--tools/editor/property_editor.cpp200
-rw-r--r--tools/editor/property_editor.h13
-rw-r--r--tools/editor/scene_tree_dock.cpp350
-rw-r--r--tools/editor/scene_tree_dock.h10
-rw-r--r--tools/editor/scene_tree_editor.cpp131
-rw-r--r--tools/editor/scene_tree_editor.h6
-rw-r--r--tools/editor/scenes_dock.cpp145
-rw-r--r--tools/editor/scenes_dock.h3
18 files changed, 1002 insertions, 66 deletions
diff --git a/tools/doc/doc_data.cpp b/tools/doc/doc_data.cpp
index 30d419a9f3..0c4751979c 100644
--- a/tools/doc/doc_data.cpp
+++ b/tools/doc/doc_data.cpp
@@ -989,6 +989,8 @@ Error DocData::save(const String& p_path) {
PropertyDoc &p=c.properties[i];
_write_string(f,2,"<member name=\""+p.name+"\" type=\""+p.type+"\">");
+ if (p.description!="")
+ _write_string(f,3,p.description.xml_escape());
_write_string(f,2,"</member>");
}
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index 2736a75ac3..c9cec3b7f4 100644
--- a/tools/editor/editor_node.cpp
+++ b/tools/editor/editor_node.cpp
@@ -523,7 +523,7 @@ void EditorNode::save_resource(const Ref<Resource>& p_resource) {
}
}
-void EditorNode::save_resource_as(const Ref<Resource>& p_resource) {
+void EditorNode::save_resource_as(const Ref<Resource>& p_resource,const String& p_at_path) {
file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
bool relpaths = (p_resource->has_meta("__editor_relpaths__") && p_resource->get_meta("__editor_relpaths__").operator bool());
@@ -546,7 +546,21 @@ void EditorNode::save_resource_as(const Ref<Resource>& p_resource) {
}
//file->set_current_path(current_path);
- if (p_resource->get_path()!="") {
+
+ if (p_at_path!=String()) {
+
+ file->set_current_dir(p_at_path);
+ if (p_resource->get_path().is_resource_file()) {
+ file->set_current_file(p_resource->get_path().get_file());
+ } else {
+ if (extensions.size()) {
+ file->set_current_file("new_"+p_resource->get_type().to_lower()+"."+preferred.front()->get().to_lower());
+ } else {
+ file->set_current_file(String());
+ }
+ }
+ } else if (p_resource->get_path()!="") {
+
file->set_current_path(p_resource->get_path());
if (extensions.size()) {
String ext=p_resource->get_path().extension().to_lower();
@@ -3725,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);
}
@@ -4881,6 +4894,114 @@ void EditorNode::remove_control_from_dock(Control* p_control) {
_update_dock_slots_visibility();
}
+Variant EditorNode::drag_resource(const Ref<Resource>& p_res,Control* p_from) {
+
+
+ Control *drag_control = memnew( Control );
+ TextureFrame *drag_preview = memnew( TextureFrame );
+ Label* label=memnew( Label );
+
+ Ref<Texture> preview;
+
+ {
+ //todo make proper previews
+ Ref<ImageTexture> pic = gui_base->get_icon("FileBig","EditorIcons");
+ Image img = pic->get_data();
+ img.resize(48,48); //meh
+ Ref<ImageTexture> resized_pic = Ref<ImageTexture>( memnew( ImageTexture) );
+ resized_pic->create_from_image(img);
+ preview=resized_pic;
+ }
+
+ drag_preview->set_texture(preview);
+ drag_control->add_child(drag_preview);
+ if (p_res->get_path().is_resource_file()) {
+ label->set_text(p_res->get_path().get_file());
+ } else if (p_res->get_name()!="") {
+ label->set_text(p_res->get_name());
+ } else {
+ label->set_text(p_res->get_type());
+
+ }
+
+ drag_control->add_child(label);
+
+ p_from->set_drag_preview(drag_control); //wait until it enters scene
+
+ label->set_pos( Point2((preview->get_width()-label->get_minimum_size().width)/2,preview->get_height()) );
+
+ Dictionary drag_data;
+ drag_data["type"]="resource";
+ drag_data["resource"]=p_res;
+ drag_data["from"]=p_from;
+
+
+ return drag_data;
+
+}
+
+Variant EditorNode::drag_files(const Vector<String>& p_files, Control *p_from){
+
+ VBoxContainer *files = memnew( VBoxContainer );
+
+ int max_files=6;
+
+ for(int i=0;i<MIN(max_files,p_files.size());i++) {
+
+ Label* label=memnew( Label );
+ label->set_text(p_files[i].get_file());
+ files->add_child(label);
+ }
+
+ if (p_files.size()>max_files) {
+
+ Label* label=memnew( Label );
+ label->set_text(itos(p_files.size()-max_files)+" "+TTR("More File(s)"));
+ files->add_child(label);
+
+ }
+ Dictionary drag_data;
+ drag_data["type"]="files";
+ drag_data["files"]=p_files;
+ drag_data["from"]=p_from;
+
+ p_from->set_drag_preview(files); //wait until it enters scene
+
+ return drag_data;
+
+}
+
+Variant EditorNode::drag_files_and_dirs(const Vector<String>& p_files, Control *p_from){
+
+ VBoxContainer *files = memnew( VBoxContainer );
+
+ int max_files=6;
+
+ for(int i=0;i<MIN(max_files,p_files.size());i++) {
+
+ Label* label=memnew( Label );
+ label->set_text(p_files[i].get_file());
+ files->add_child(label);
+ }
+
+ if (p_files.size()>max_files) {
+
+ Label* label=memnew( Label );
+ label->set_text(itos(p_files.size()-max_files)+" "+TTR("More File(s) and/or Directory(s)"));
+ files->add_child(label);
+
+ }
+ Dictionary drag_data;
+ drag_data["type"]="files_and_dirs";
+ drag_data["files"]=p_files;
+ drag_data["from"]=p_from;
+
+ p_from->set_drag_preview(files); //wait until it enters scene
+
+ return drag_data;
+
+}
+
void EditorNode::_bind_methods() {
diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h
index c3b7a817c5..cfec15c383 100644
--- a/tools/editor/editor_node.h
+++ b/tools/editor/editor_node.h
@@ -584,6 +584,9 @@ public:
static void add_editor_plugin(EditorPlugin *p_editor);
static void remove_editor_plugin(EditorPlugin *p_editor);
+
+
+
void add_control_to_dock(DockSlot p_slot,Control* p_control);
void remove_control_from_dock(Control* p_control);
@@ -599,7 +602,7 @@ public:
void save_resource_in_path(const Ref<Resource>& p_resource,const String& p_path);
void save_resource(const Ref<Resource>& p_resource);
- void save_resource_as(const Ref<Resource>& p_resource);
+ void save_resource_as(const Ref<Resource>& p_resource, const String &p_at_path=String());
static bool has_unsaved_changes() { return singleton->unsaved_cache; }
@@ -641,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(); }
@@ -696,6 +699,11 @@ public:
void hide_bottom_panel();
void remove_bottom_panel_item(Control *p_item);
+ Variant drag_resource(const Ref<Resource>& p_res,Control* p_from);
+ Variant drag_files(const Vector<String>& p_files,Control* p_from);
+ Variant drag_files_and_dirs(const Vector<String>& p_files,Control* p_from);
+
+
EditorNode();
~EditorNode();
void get_singleton(const char* arg1, bool arg2);
diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp
index 29f0af5aa4..b9b6dc5616 100644
--- a/tools/editor/editor_settings.cpp
+++ b/tools/editor/editor_settings.cpp
@@ -426,6 +426,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
set("text_editor/create_signal_callbacks",true);
set("text_editor/autosave_interval_secs",0);
+ set("text_editor/caret_blink", false);
+ set("text_editor/caret_blink_speed", 0.65);
+ hints["text_editor/caret_blink_speed"]=PropertyInfo(Variant::REAL,"text_editor/caret_blink_speed",PROPERTY_HINT_RANGE,"0.1, 10, 0.1");
+
set("text_editor/font","");
hints["text_editor/font"]=PropertyInfo(Variant::STRING,"text_editor/font",PROPERTY_HINT_GLOBAL_FILE,"*.fnt");
set("text_editor/auto_brace_complete", false);
@@ -459,6 +463,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
set("2d_editor/bone_color2",Color(0.75,0.75,0.75,0.9));
set("2d_editor/bone_selected_color",Color(0.9,0.45,0.45,0.9));
set("2d_editor/bone_ik_color",Color(0.9,0.9,0.45,0.9));
+
+ set("2d_editor/keep_margins_when_changing_anchors", false);
set("game_window_placement/rect",0);
hints["game_window_placement/rect"]=PropertyInfo(Variant::INT,"game_window_placement/rect",PROPERTY_HINT_ENUM,"Default,Centered,Custom Position,Force Maximized,Force Full Screen");
diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp
index 745266e19a..77bd5d0fef 100644
--- a/tools/editor/plugins/animation_player_editor_plugin.cpp
+++ b/tools/editor/plugins/animation_player_editor_plugin.cpp
@@ -116,7 +116,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
tool_anim->set_icon(get_icon("Tools","EditorIcons"));
tool_anim->get_popup()->connect("item_pressed",this,"_animation_tool_menu");
- blend_editor.next->connect("text_changed",this,"_blend_editor_next_changed");
+ blend_editor.next->connect("item_selected", this, "_blend_editor_next_changed");
nodename->set_icon(get_icon("AnimationPlayer","EditorIcons"));
@@ -536,14 +536,19 @@ void AnimationPlayerEditor::_animation_name_edited() {
}
-void AnimationPlayerEditor::_blend_editor_next_changed(const String& p_string) {
+void AnimationPlayerEditor::_blend_editor_next_changed(const int p_idx) {
if (animation->get_item_count()==0)
return;
String current = animation->get_item_text(animation->get_selected());
- player->animation_set_next(current,p_string);
+ undo_redo->create_action(TTR("Blend Next Changed"));
+ undo_redo->add_do_method(player,"animation_set_next",current,blend_editor.next->get_item_text(p_idx));
+ undo_redo->add_undo_method(player,"animation_set_next",current,player->animation_get_next(current));
+ undo_redo->add_do_method(this,"_animation_player_changed",player);
+ undo_redo->add_undo_method(this,"_animation_player_changed",player);
+ undo_redo->commit_action();
}
void AnimationPlayerEditor::_animation_blend() {
@@ -569,6 +574,11 @@ void AnimationPlayerEditor::_animation_blend() {
TreeItem *root = blend_editor.tree->create_item();
updating_blends=true;
+ int i = 0;
+ bool anim_found = false;
+ blend_editor.next->clear();
+ blend_editor.next->add_item("", i);
+
for(List<StringName>::Element *E=anims.front();E;E=E->next()) {
String to=E->get();
@@ -579,9 +589,20 @@ void AnimationPlayerEditor::_animation_blend() {
blend->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
blend->set_range_config(1,0,3600,0.001);
blend->set_range(1,player->get_blend_time(current,to));
+
+ i++;
+ blend_editor.next->add_item(to, i);
+ if (to == player->animation_get_next(current)) {
+ blend_editor.next->select(i);
+ anim_found = true;
+ }
}
- blend_editor.next->set_text( player->animation_get_next(current) );
+ // make sure we reset it else it becomes out of sync and could contain a deleted animation
+ if (!anim_found) {
+ blend_editor.next->select(0);
+ player->animation_set_next(current, blend_editor.next->get_item_text(0));
+ }
updating_blends=false;
}
@@ -913,6 +934,7 @@ void AnimationPlayerEditor::_animation_duplicate() {
undo_redo->create_action(TTR("Duplicate Animation"));
undo_redo->add_do_method(player,"add_animation",new_name,new_anim);
undo_redo->add_undo_method(player,"remove_animation",new_name);
+ undo_redo->add_do_method(player,"animation_set_next",new_name,player->animation_get_next(current));
undo_redo->add_do_method(this,"_animation_player_changed",player);
undo_redo->add_undo_method(this,"_animation_player_changed",player);
undo_redo->commit_action();
@@ -1438,7 +1460,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
blend_editor.tree = memnew( Tree );
blend_editor.tree->set_columns(2);
blend_vb->add_margin_child(TTR("Blend Times: "),blend_editor.tree,true);
- blend_editor.next = memnew( LineEdit );
+ blend_editor.next = memnew( OptionButton );
blend_vb->add_margin_child(TTR("Next (Auto Queue):"),blend_editor.next);
blend_editor.dialog->set_title(TTR("Cross-Animation Blend Times"));
updating_blends=false;
diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h
index 5f3c8ec49b..9583f3e663 100644
--- a/tools/editor/plugins/animation_player_editor_plugin.h
+++ b/tools/editor/plugins/animation_player_editor_plugin.h
@@ -103,7 +103,7 @@ class AnimationPlayerEditor : public VBoxContainer {
AcceptDialog * dialog;
Tree *tree;
- LineEdit *next;
+ OptionButton *next;
} blend_editor;
@@ -146,7 +146,7 @@ class AnimationPlayerEditor : public VBoxContainer {
void _dialog_action(String p_file);
void _seek_frame_changed(const String& p_frame);
void _seek_value_changed(float p_value);
- void _blend_editor_next_changed(const String& p_string);
+ void _blend_editor_next_changed(const int p_idx);
void _list_changed();
void _update_animation();
diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp
index 7ece65e75a..0213dbda59 100644
--- a/tools/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/tools/editor/plugins/canvas_item_editor_plugin.cpp
@@ -572,6 +572,8 @@ bool CanvasItemEditor::_select(CanvasItem *item, Point2 p_click_pos, bool p_appe
_append_canvas_item(item);
viewport->update();
+ return true;
+
} else {
//regular selection
diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp
index eaf08ca1c0..d8d5fddfe9 100644
--- a/tools/editor/plugins/script_editor_plugin.cpp
+++ b/tools/editor/plugins/script_editor_plugin.cpp
@@ -1967,6 +1967,8 @@ void ScriptEditor::edit(const Ref<Script>& p_script) {
ste->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers"));
ste->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting"));
ste->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences"));
+ ste->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink"));
+ ste->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed"));
ste->get_text_edit()->set_callhint_settings(
EditorSettings::get_singleton()->get("text_editor/put_callhint_tooltip_below_current_line"),
EditorSettings::get_singleton()->get("text_editor/callhint_tooltip_offset"));
@@ -2114,6 +2116,8 @@ void ScriptEditor::_editor_settings_changed() {
ste->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers"));
ste->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting"));
ste->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences"));
+ ste->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink"));
+ ste->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed"));
}
}
diff --git a/tools/editor/plugins/shader_editor_plugin.cpp b/tools/editor/plugins/shader_editor_plugin.cpp
index 3399114402..8a65a3641f 100644
--- a/tools/editor/plugins/shader_editor_plugin.cpp
+++ b/tools/editor/plugins/shader_editor_plugin.cpp
@@ -368,6 +368,8 @@ void ShaderEditor::_editor_settings_changed() {
vertex_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers"));
vertex_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting"));
vertex_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences"));
+ vertex_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink"));
+ vertex_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed"));
fragment_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete"));
fragment_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file"));
@@ -376,6 +378,8 @@ void ShaderEditor::_editor_settings_changed() {
fragment_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers"));
fragment_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting"));
fragment_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences"));
+ fragment_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink"));
+ fragment_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed"));
light_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete"));
light_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/scroll_past_end_of_file"));
@@ -384,6 +388,8 @@ void ShaderEditor::_editor_settings_changed() {
light_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/show_line_numbers"));
light_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/syntax_highlighting"));
light_editor->get_text_edit()->set_highlight_all_occurrences(EditorSettings::get_singleton()->get("text_editor/highlight_all_occurrences"));
+ light_editor->get_text_edit()->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/caret_blink"));
+ light_editor->get_text_edit()->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/caret_blink_speed"));
}
void ShaderEditor::_bind_methods() {
diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp
index eff4d3da1b..adb15c1f00 100644
--- a/tools/editor/project_export.cpp
+++ b/tools/editor/project_export.cpp
@@ -1310,11 +1310,18 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
group_lossy_quality = memnew( HSlider );
group_lossy_quality->set_min(0.1);
group_lossy_quality->set_max(1.0);
- group_lossy_quality->set_step(0.1);
+ group_lossy_quality->set_step(0.01);
group_lossy_quality->set_val(0.7);
- group_options->add_margin_child(TTR("Lossy Quality:"),group_lossy_quality);
group_lossy_quality->connect("value_changed",this,"_quality_edited");
+ HBoxContainer *gqhb = memnew( HBoxContainer );
+ SpinBox *gqspin = memnew( SpinBox );
+ group_lossy_quality->share(gqspin);
+ group_lossy_quality->set_h_size_flags(SIZE_EXPAND_FILL);
+ gqhb->add_child(group_lossy_quality);
+ gqhb->add_child(gqspin);
+ group_options->add_margin_child(TTR("Lossy Quality:"),gqhb);
+
group_atlas = memnew(CheckButton);
group_atlas->set_pressed(true);
group_options->add_margin_child(TTR("Atlas:"),group_atlas);
diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp
index 7c5aca579c..6f80910150 100644
--- a/tools/editor/property_editor.cpp
+++ b/tools/editor/property_editor.cpp
@@ -43,7 +43,8 @@
#include "array_property_edit.h"
#include "editor_help.h"
#include "scene/resources/packed_scene.h"
-
+#include "scene/main/viewport.h"
+#include "editor_file_system.h"
void CustomPropertyEditor::_notification(int p_what) {
@@ -224,6 +225,10 @@ void CustomPropertyEditor::_menu_option(int p_which) {
}
+void CustomPropertyEditor::hide_menu() {
+ menu->hide();
+}
+
Variant CustomPropertyEditor::get_variant() const {
return v;
@@ -2257,6 +2262,179 @@ void PropertyEditor::_check_reload_status(const String&p_name, TreeItem* item) {
}
}
+
+
+bool PropertyEditor::_is_drop_valid(const Dictionary& p_drag_data, const Dictionary& p_item_data) const {
+
+ Dictionary d = p_item_data;
+
+ if (d.has("type")) {
+
+ int type = d["type"];
+ if (type==Variant::OBJECT && d.has("hint") && d.has("hint_text") && int(d["hint"])==PROPERTY_HINT_RESOURCE_TYPE) {
+
+
+ String allowed_type=d["hint_text"];
+
+ Dictionary drag_data = p_drag_data;
+ if (drag_data.has("type") && String(drag_data["type"])=="resource") {
+ Ref<Resource> res = drag_data["resource"];
+ for(int i=0;i<allowed_type.get_slice_count(",");i++) {
+ String at = allowed_type.get_slice(",",i).strip_edges();
+ if (res.is_valid() && ObjectTypeDB::is_type(res->get_type(),at)) {
+ return true;
+ }
+ }
+
+ }
+ if (drag_data.has("type") && String(drag_data["type"])=="files") {
+
+ Vector<String> files = drag_data["files"];
+
+ if (files.size()==1) {
+ String file = files[0];
+ String ftype = EditorFileSystem::get_singleton()->get_file_type(file);
+ if (ftype!="") {
+
+ for(int i=0;i<allowed_type.get_slice_count(",");i++) {
+ String at = allowed_type.get_slice(",",i).strip_edges();
+ if (ObjectTypeDB::is_type(ftype,at)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ return false;
+
+}
+void PropertyEditor::_mark_drop_fields(TreeItem* p_at) {
+
+ if (_is_drop_valid(get_viewport()->gui_get_drag_data(),p_at->get_metadata(0)))
+ p_at->set_custom_bg_color(1,Color(0.7,0.5,0.2),true);
+
+ if (p_at->get_children()) {
+ _mark_drop_fields(p_at->get_children());
+ }
+
+ if (p_at->get_next()) {
+ _mark_drop_fields(p_at->get_next());
+ }
+}
+
+Variant PropertyEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) {
+
+ TreeItem *item = tree->get_item_at_pos(p_point);
+ if (!item)
+ return Variant();
+
+ int col = tree->get_column_at_pos(p_point);
+ if (col!=1)
+ return Variant();
+
+
+ Dictionary d = item->get_metadata(0);
+ if (!d.has("name"))
+ return Variant();
+
+ Variant val = obj->get(d["name"]);
+
+ if (val.get_type()==Variant::OBJECT) {
+ RES res = val;
+ if (res.is_valid()) {
+
+ custom_editor->hide_menu();
+ return EditorNode::get_singleton()->drag_resource(res,p_from);
+ }
+ }
+
+ return Variant();
+}
+
+bool PropertyEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{
+
+ TreeItem *item = tree->get_item_at_pos(p_point);
+ if (!item)
+ return false;
+
+ int col = tree->get_column_at_pos(p_point);
+ if (col!=1)
+ return false;
+
+ return _is_drop_valid(p_data,item->get_metadata(0));
+
+}
+void PropertyEditor::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){
+
+ TreeItem *item = tree->get_item_at_pos(p_point);
+ if (!item)
+ return;
+
+ int col = tree->get_column_at_pos(p_point);
+ if (col!=1)
+ return;
+
+ if (!_is_drop_valid(p_data,item->get_metadata(0)))
+ return;
+
+ Dictionary d = item->get_metadata(0);
+
+ if (!d.has("name"))
+ return;
+
+ String name=d["name"];
+
+ Dictionary drag_data = p_data;
+ if (drag_data.has("type") && String(drag_data["type"])=="resource") {
+ Ref<Resource> res = drag_data["resource"];
+ if (res.is_valid()) {
+ _edit_set(name,res);
+ return;
+ }
+ }
+
+ if (drag_data.has("type") && String(drag_data["type"])=="files") {
+
+ Vector<String> files = drag_data["files"];
+
+ if (files.size()==1) {
+ String file = files[0];
+ RES res = ResourceLoader::load(file);
+ if (res.is_valid()) {
+ _edit_set(name,res);
+ return;
+ }
+ }
+ }
+}
+
+
+void PropertyEditor::_clear_drop_fields(TreeItem* p_at) {
+
+ Dictionary d = p_at->get_metadata(0);
+
+ if (d.has("type")) {
+
+ int type = d["type"];
+ if (type==Variant::OBJECT) {
+ p_at->clear_custom_bg_color(1);
+ }
+
+ }
+
+ if (p_at->get_children()) {
+ _clear_drop_fields(p_at->get_children());
+ }
+
+ if (p_at->get_next()) {
+ _clear_drop_fields(p_at->get_next());
+ }
+}
+
void PropertyEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
@@ -2270,6 +2448,20 @@ void PropertyEditor::_notification(int p_what) {
}
+ if (p_what==NOTIFICATION_DRAG_BEGIN) {
+
+ if (is_visible() && tree->get_root()) {
+ _mark_drop_fields(tree->get_root());
+ }
+ }
+
+ if (p_what==NOTIFICATION_DRAG_END) {
+ if (is_visible() && tree->get_root()) {
+ _clear_drop_fields(tree->get_root());
+ }
+
+ }
+
if (p_what==NOTIFICATION_FIXED_PROCESS) {
@@ -3661,6 +3853,10 @@ void PropertyEditor::_bind_methods() {
ObjectTypeDB::bind_method( "_filter_changed",&PropertyEditor::_filter_changed);
ObjectTypeDB::bind_method( "update_tree",&PropertyEditor::update_tree);
+ ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &PropertyEditor::get_drag_data_fw);
+ ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &PropertyEditor::can_drop_data_fw);
+ ObjectTypeDB::bind_method(_MD("drop_data_fw"), &PropertyEditor::drop_data_fw);
+
ADD_SIGNAL( MethodInfo("property_toggled",PropertyInfo( Variant::STRING, "property"),PropertyInfo( Variant::BOOL, "value")));
ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
ADD_SIGNAL( MethodInfo("property_keyed",PropertyInfo( Variant::STRING, "property")));
@@ -3778,6 +3974,8 @@ PropertyEditor::PropertyEditor() {
tree->connect("item_edited", this,"_item_edited",varray(),CONNECT_DEFERRED);
tree->connect("cell_selected", this,"_item_selected");
+ tree->set_drag_forwarding(this);
+
set_fixed_process(true);
custom_editor = memnew( CustomPropertyEditor );
diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h
index 693bfb3efd..ac58011d43 100644
--- a/tools/editor/property_editor.h
+++ b/tools/editor/property_editor.h
@@ -137,6 +137,10 @@ protected:
static void _bind_methods();
public:
+
+
+ void hide_menu();
+
Variant get_variant() const;
String get_name() const;
@@ -219,6 +223,15 @@ class PropertyEditor : public Control {
void _filter_changed(const String& p_text);
+ void _mark_drop_fields(TreeItem* p_at);
+ void _clear_drop_fields(TreeItem* p_at);
+
+ bool _is_drop_valid(const Dictionary& p_drag_data, const Dictionary& p_item_data) const;
+ Variant get_drag_data_fw(const Point2& p_point,Control* p_from);
+ bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const;
+ void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from);
+
+
UndoRedo *undo_redo;
protected:
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;
diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h
index 114e2c5c97..5dc1e3e12e 100644
--- a/tools/editor/scene_tree_dock.h
+++ b/tools/editor/scene_tree_dock.h
@@ -102,6 +102,8 @@ class SceneTreeDock : public VBoxContainer {
Node *_duplicate(Node *p_node, Map<Node*,Node*> &duplimap);
void _node_reparent(NodePath p_path, bool p_keep_global_xform);
+ void _do_reparent(Node* p_new_parent, int p_position_in_parent, Vector<Node*> p_nodes, bool p_keep_global_xform);
+
void _set_owners(Node *p_owner, const Array& p_nodes);
void _load_request(const String& p_path);
void _script_open_request(const Ref<Script>& p_script);
@@ -128,6 +130,11 @@ 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:
void _notification(int p_what);
@@ -136,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);
diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp
index 6d13f74e4d..fd79460aa8 100644
--- a/tools/editor/scene_tree_editor.cpp
+++ b/tools/editor/scene_tree_editor.cpp
@@ -784,6 +784,129 @@ void SceneTreeEditor::_cell_collapsed(Object *p_obj) {
}
+Variant SceneTreeEditor::get_drag_data_fw(const Point2& p_point,Control* p_from) {
+ if (!can_rename)
+ return Variant(); //not editable tree
+
+ Vector<Node*> selected;
+ Vector<Ref<Texture> > icons;
+ TreeItem *next=tree->get_next_selected(NULL);
+ while (next) {
+
+ NodePath np = next->get_metadata(0);
+
+ Node *n=get_node(np);
+ if (n) {
+
+ selected.push_back(n);
+ icons.push_back(next->get_icon(0));
+ }
+ next=tree->get_next_selected(next);
+ }
+
+ if (selected.empty())
+ return Variant();
+
+ VBoxContainer *vb = memnew( VBoxContainer );
+ Array objs;
+ for(int i=0;i<selected.size();i++) {
+
+ HBoxContainer *hb = memnew( HBoxContainer );
+ TextureFrame *tf = memnew(TextureFrame);
+ tf->set_texture(icons[i]);
+ hb->add_child(tf);
+ Label *label = memnew( Label( selected[i]->get_name() ) );
+ hb->add_child(label);
+ vb->add_child(hb);
+ NodePath p = selected[i]->get_path();
+ objs.push_back(p);
+ }
+
+ set_drag_preview(vb);
+ Dictionary drag_data;
+ drag_data["type"]="nodes";
+ drag_data["nodes"]=objs;
+
+ tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN|Tree::DROP_MODE_ON_ITEM);
+
+
+ return drag_data;
+}
+
+bool SceneTreeEditor::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const {
+
+ if (!can_rename)
+ return false; //not editable tree
+
+ Dictionary d=p_data;
+ if (!d.has("type"))
+ return false;
+
+ 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) {
+
+ if (!can_drop_data_fw(p_point,p_data,p_from))
+ return;
+
+ TreeItem *item = tree->get_item_at_pos(p_point);
+ if (!item)
+ return;
+ int section = tree->get_drop_section_at_pos(p_point);
+ if (section<-1)
+ return;
+
+ NodePath np = item->get_metadata(0);
+ Node *n=get_node(np);
+ if (!n)
+ return;
+
+ Dictionary d=p_data;
+
+ if (String(d["type"])=="nodes") {
+ Array nodes=d["nodes"];
+ emit_signal("nodes_rearranged",nodes,np,section);
+ }
+
+ if (String(d["type"])=="files") {
+
+ emit_signal("files_dropped",d["files"],np,section);
+ }
+
+}
void SceneTreeEditor::_bind_methods() {
@@ -804,10 +927,16 @@ void SceneTreeEditor::_bind_methods() {
ObjectTypeDB::bind_method("_node_script_changed",&SceneTreeEditor::_node_script_changed);
ObjectTypeDB::bind_method("_node_visibility_changed",&SceneTreeEditor::_node_visibility_changed);
+ ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw);
+ ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw);
+ ObjectTypeDB::bind_method(_MD("drop_data_fw"), &SceneTreeEditor::drop_data_fw);
+
ADD_SIGNAL( MethodInfo("node_selected") );
ADD_SIGNAL( MethodInfo("node_renamed") );
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") );
@@ -846,6 +975,8 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open
add_child( tree );
+ tree->set_drag_forwarding(this);
+
tree->connect("cell_selected", this,"_selected_changed");
tree->connect("item_edited", this,"_renamed",varray(),CONNECT_DEFERRED);
tree->connect("multi_selected",this,"_cell_multi_selected");
diff --git a/tools/editor/scene_tree_editor.h b/tools/editor/scene_tree_editor.h
index 27ccaaae01..283db280ed 100644
--- a/tools/editor/scene_tree_editor.h
+++ b/tools/editor/scene_tree_editor.h
@@ -111,8 +111,14 @@ class SceneTreeEditor : public Control {
void _node_visibility_changed(Node *p_node);
void _subscene_option(int p_idx);
+
void _selection_changed();
Node *get_scene_node();
+
+ Variant get_drag_data_fw(const Point2& p_point,Control* p_from);
+ bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const;
+ void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from);
+
public:
diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp
index 7cb0a094b2..c03142a3e7 100644
--- a/tools/editor/scenes_dock.cpp
+++ b/tools/editor/scenes_dock.cpp
@@ -451,7 +451,7 @@ void ScenesDock::_update_files(bool p_keep_selection) {
img.resize(thumbnail_size,thumbnail_size);
Ref<ImageTexture> resized_folder = Ref<ImageTexture>( memnew( ImageTexture));
resized_folder->create_from_image(img,0);
- Theme::get_default()->set_icon(TTR("ResizedFolder"),"EditorIcons",resized_folder);
+ Theme::get_default()->set_icon("ResizedFolder","EditorIcons",resized_folder);
}
folder_thumbnail = get_icon("ResizedFolder","EditorIcons");
@@ -462,7 +462,7 @@ void ScenesDock::_update_files(bool p_keep_selection) {
img.resize(thumbnail_size,thumbnail_size);
Ref<ImageTexture> resized_file = Ref<ImageTexture>( memnew( ImageTexture));
resized_file->create_from_image(img,0);
- Theme::get_default()->set_icon(TTR("ResizedFile"),"EditorIcons",resized_file);
+ Theme::get_default()->set_icon("ResizedFile","EditorIcons",resized_file);
}
file_thumbnail = get_icon("ResizedFile","EditorIcons");
@@ -1073,6 +1073,142 @@ void ScenesDock::set_use_thumbnails(bool p_use) {
display_mode->set_pressed(!p_use);
}
+
+Variant ScenesDock::get_drag_data_fw(const Point2& p_point,Control* p_from) {
+
+ if (p_from==files) {
+
+ List<int> seldirs;
+ List<int> selfiles;
+
+ for (int i = 0; i<files->get_item_count(); i++) {
+ if (files->is_selected(i)) {
+ String path = files->get_item_metadata(i);
+ if (path.ends_with("/"))
+ seldirs.push_back(i);
+ else
+ selfiles.push_back(i);
+ }
+ }
+
+ if (seldirs.empty() && selfiles.empty())
+ return Variant();
+ //if (seldirs.size() && selfiles.size())
+ // return Variant(); //can't really mix files and dirs (i think?) - yes you can, commenting
+
+ /*if (selfiles.size()==1) {
+ Ref<Resource> resource = ResourceLoader::load(files->get_item_metadata(selfiles.front()->get()));
+ if (resource.is_valid()) {
+ return EditorNode::get_singleton()->drag_resource(resource,p_from);
+ }
+ }*/
+
+ if (selfiles.size()>0 && seldirs.size()==0) {
+ Vector<String> fnames;
+ for(List<int>::Element *E=selfiles.front();E;E=E->next()) {
+ fnames.push_back(files->get_item_metadata(E->get()));
+ }
+ return EditorNode::get_singleton()->drag_files(fnames,p_from);
+ }
+
+ if (selfiles.size()>0 || seldirs.size()>0) {
+ Vector<String> fnames;
+ for(List<int>::Element *E=selfiles.front();E;E=E->next()) {
+ fnames.push_back(files->get_item_metadata(E->get()));
+ }
+ for(List<int>::Element *E=seldirs.front();E;E=E->next()) {
+ fnames.push_back(files->get_item_metadata(E->get()));
+ }
+ return EditorNode::get_singleton()->drag_files_and_dirs(fnames,p_from);
+ }
+
+ }
+
+ return Variant();
+}
+
+bool ScenesDock::can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const{
+
+ Dictionary drag_data = p_data;
+
+
+ if (drag_data.has("type") && String(drag_data["type"])=="resource") {
+ return true;
+ }
+
+ if (drag_data.has("type") && ( String(drag_data["type"])=="files" || String(drag_data["type"])=="files_and_dirs")) {
+
+ Vector<String> fnames = drag_data["files"];
+
+ if (p_from==files) {
+
+ int at_pos = files->get_item_at_pos(p_point);
+ if (at_pos!=-1) {
+
+ String dir = files->get_item_metadata(at_pos);
+ if (dir.ends_with("/"))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void ScenesDock::drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from){
+
+ if (!can_drop_data_fw(p_point,p_data,p_from))
+ return;
+ Dictionary drag_data = p_data;
+
+ if (drag_data.has("type") && String(drag_data["type"])=="resource") {
+ Ref<Resource> res = drag_data["resource"];
+
+ if (!res.is_valid()) {
+ return;
+ }
+
+ String save_path=path;
+
+ int at_pos = files->get_item_at_pos(p_point);
+ if (at_pos!=-1) {
+ String to_dir = files->get_item_metadata(at_pos);
+ if (to_dir.ends_with("/")) {
+ save_path=to_dir;
+ if (save_path!="res://")
+ save_path=save_path.substr(0,save_path.length()-1);
+ }
+
+ }
+
+ EditorNode::get_singleton()->save_resource_as(res,save_path);
+ return;
+ }
+
+ if (drag_data.has("type") && ( String(drag_data["type"])=="files" || String(drag_data["type"])=="files_and_dirs")) {
+
+ int at_pos = files->get_item_at_pos(p_point);
+ ERR_FAIL_COND(at_pos==-1);
+ String to_dir = files->get_item_metadata(at_pos);
+ ERR_FAIL_COND(!to_dir.ends_with("/"));
+
+ Vector<String> fnames = drag_data["files"];
+ move_files.clear();
+ move_dirs.clear();
+
+ for(int i=0;i<fnames.size();i++) {
+ if (fnames[i].ends_with("/"))
+ move_dirs.push_back(fnames[i]);
+ else
+ move_files.push_back(fnames[i]);
+ }
+
+ _move_operation(to_dir);
+ }
+
+}
+
+
void ScenesDock::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_update_tree"),&ScenesDock::_update_tree);
@@ -1096,6 +1232,10 @@ void ScenesDock::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_move_operation"), &ScenesDock::_move_operation);
ObjectTypeDB::bind_method(_MD("_rename_operation"), &ScenesDock::_rename_operation);
+ ObjectTypeDB::bind_method(_MD("get_drag_data_fw"), &ScenesDock::get_drag_data_fw);
+ ObjectTypeDB::bind_method(_MD("can_drop_data_fw"), &ScenesDock::can_drop_data_fw);
+ ObjectTypeDB::bind_method(_MD("drop_data_fw"), &ScenesDock::drop_data_fw);
+
ADD_SIGNAL(MethodInfo("instance"));
ADD_SIGNAL(MethodInfo("open"));
@@ -1199,6 +1339,7 @@ ScenesDock::ScenesDock(EditorNode *p_editor) {
files = memnew( ItemList );
files->set_v_size_flags(SIZE_EXPAND_FILL);
files->set_select_mode(ItemList::SELECT_MULTI);
+ files->set_drag_forwarding(this);
path_hb = memnew( HBoxContainer );
button_back = memnew( ToolButton );
diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h
index a630d2506d..86196b7ccd 100644
--- a/tools/editor/scenes_dock.h
+++ b/tools/editor/scenes_dock.h
@@ -142,6 +142,9 @@ class ScenesDock : public VBoxContainer {
void _instance_pressed();
void _open_pressed();
+ Variant get_drag_data_fw(const Point2& p_point,Control* p_from);
+ bool can_drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from) const;
+ void drop_data_fw(const Point2& p_point,const Variant& p_data,Control* p_from);
protected:
void _notification(int p_what);