diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/doc/doc_data.cpp | 2 | ||||
| -rw-r--r-- | tools/editor/editor_node.cpp | 131 | ||||
| -rw-r--r-- | tools/editor/editor_node.h | 12 | ||||
| -rw-r--r-- | tools/editor/editor_settings.cpp | 6 | ||||
| -rw-r--r-- | tools/editor/plugins/animation_player_editor_plugin.cpp | 32 | ||||
| -rw-r--r-- | tools/editor/plugins/animation_player_editor_plugin.h | 4 | ||||
| -rw-r--r-- | tools/editor/plugins/canvas_item_editor_plugin.cpp | 2 | ||||
| -rw-r--r-- | tools/editor/plugins/script_editor_plugin.cpp | 4 | ||||
| -rw-r--r-- | tools/editor/plugins/shader_editor_plugin.cpp | 6 | ||||
| -rw-r--r-- | tools/editor/project_export.cpp | 11 | ||||
| -rw-r--r-- | tools/editor/property_editor.cpp | 200 | ||||
| -rw-r--r-- | tools/editor/property_editor.h | 13 | ||||
| -rw-r--r-- | tools/editor/scene_tree_dock.cpp | 350 | ||||
| -rw-r--r-- | tools/editor/scene_tree_dock.h | 10 | ||||
| -rw-r--r-- | tools/editor/scene_tree_editor.cpp | 131 | ||||
| -rw-r--r-- | tools/editor/scene_tree_editor.h | 6 | ||||
| -rw-r--r-- | tools/editor/scenes_dock.cpp | 145 | ||||
| -rw-r--r-- | tools/editor/scenes_dock.h | 3 |
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); |