diff options
author | Kostadin Damyanov <maxmight@gmail.com> | 2015-09-05 12:03:17 +0300 |
---|---|---|
committer | Kostadin Damyanov <maxmight@gmail.com> | 2015-09-05 12:03:17 +0300 |
commit | c5f574b914b3cb11d97ae616df4a0bced45bb17c (patch) | |
tree | d7b70f0842c00c480ce10039b873a1dddd894a6c /tools | |
parent | 2a757a6ad4ef4e7767b7d3ef7e177ec6613ef6d1 (diff) | |
parent | b0aa49accbd7e45dae38f1bd43b0fbdd11714211 (diff) |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'tools')
69 files changed, 3507 insertions, 444 deletions
diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp index d431af6c8d..96bd1ed27d 100644 --- a/tools/editor/animation_editor.cpp +++ b/tools/editor/animation_editor.cpp @@ -33,6 +33,7 @@ #include "io/resource_saver.h" #include "pair.h" #include "scene/gui/separator.h" +#include "editor_node.h" /* Missing to fix: *Set @@ -634,9 +635,14 @@ void AnimationKeyEditor::_menu_track(int p_type) { last_menu_track_opt=p_type; switch(p_type) { - case TRACK_MENU_ADD_VALUE_TRACK: - case TRACK_MENU_ADD_TRANSFORM_TRACK: case TRACK_MENU_ADD_CALL_TRACK: { + if (root) { + call_select->popup_centered_ratio(); + break; + } + } break; + case TRACK_MENU_ADD_VALUE_TRACK: + case TRACK_MENU_ADD_TRANSFORM_TRACK: { undo_redo->create_action("Anim Add Track"); undo_redo->add_do_method(animation.ptr(),"add_track",p_type); @@ -2735,6 +2741,7 @@ void AnimationKeyEditor::_notification(int p_what) { } + call_select->connect("selected",this,"_add_call_track"); // rename_anim->set_icon( get_icon("Rename","EditorIcons") ); /* edit_anim->set_icon( get_icon("Edit","EditorIcons") ); @@ -3456,6 +3463,26 @@ void AnimationKeyEditor::_scale() { } +void AnimationKeyEditor::_add_call_track(const NodePath& p_base) { + + print_line("BASE IS "+String(p_base)); + Node* base = EditorNode::get_singleton()->get_edited_scene(); + if (!base) + return; + Node* from=base->get_node(p_base); + if (!from || !root) + return; + + NodePath path = root->get_path_to(from); + + undo_redo->create_action("Anim Add Call Track"); + undo_redo->add_do_method(animation.ptr(),"add_track",Animation::TYPE_METHOD); + undo_redo->add_do_method(animation.ptr(),"track_set_path",animation->get_track_count(),path); + undo_redo->add_undo_method(animation.ptr(),"remove_track",animation->get_track_count()); + undo_redo->commit_action(); + +} + void AnimationKeyEditor::cleanup() { set_animation(Ref<Animation>()); @@ -3503,6 +3530,7 @@ void AnimationKeyEditor::_bind_methods() { ObjectTypeDB::bind_method(_MD("_animation_optimize"),&AnimationKeyEditor::_animation_optimize); ObjectTypeDB::bind_method(_MD("_curve_transition_changed"),&AnimationKeyEditor::_curve_transition_changed); ObjectTypeDB::bind_method(_MD("_toggle_edit_curves"),&AnimationKeyEditor::_toggle_edit_curves); + ObjectTypeDB::bind_method(_MD("_add_call_track"),&AnimationKeyEditor::_add_call_track); ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) ); @@ -3815,7 +3843,9 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h scale_dialog->connect("confirmed",this,"_scale"); add_child(scale_dialog); - + call_select = memnew( SceneTreeDialog ); + add_child(call_select); + call_select->set_title("Call Functions in Which Node?"); } diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h index 35053fb6a3..4a1cc21154 100644 --- a/tools/editor/animation_editor.h +++ b/tools/editor/animation_editor.h @@ -44,7 +44,7 @@ #include "scene_tree_editor.h" #include "editor_data.h" #include "property_editor.h" - +#include "scene_tree_editor.h" class AnimationKeyEdit; class AnimationCurveEdit; @@ -206,6 +206,8 @@ class AnimationKeyEditor : public VBoxContainer { PropertyEditor *key_editor; + SceneTreeDialog *call_select; + Ref<Animation> animation; void _update_paths(); @@ -299,6 +301,8 @@ class AnimationKeyEditor : public VBoxContainer { void _toggle_edit_curves(); void _animation_len_update(); + void _add_call_track(const NodePath& p_base); + void _root_removed(); protected: diff --git a/tools/editor/array_property_edit.cpp b/tools/editor/array_property_edit.cpp new file mode 100644 index 0000000000..9cd443270b --- /dev/null +++ b/tools/editor/array_property_edit.cpp @@ -0,0 +1,231 @@ +#include "array_property_edit.h" + +#include "editor_node.h" + +#define ITEMS_PER_PAGE 100 + +Variant ArrayPropertyEdit::get_array() const{ + + Object*o = ObjectDB::get_instance(obj); + if (!o) + return Array(); + Variant arr=o->get(property); + if (!arr.is_array()) { + Variant::CallError ce; + arr=Variant::construct(default_type,NULL,0,ce); + } + return arr; +} + +void ArrayPropertyEdit::_notif_change() { + _change_notify(); +} +void ArrayPropertyEdit::_notif_changev(const String& p_v) { + + _change_notify(p_v.utf8().get_data()); +} + +void ArrayPropertyEdit::_set_size(int p_size) { + + Variant arr = get_array(); + arr.call("resize",p_size); + Object*o = ObjectDB::get_instance(obj); + if (!o) + return; + + o->set(property,arr); + +} + +void ArrayPropertyEdit::_set_value(int p_idx,const Variant& p_value) { + + Variant arr = get_array(); + arr.set(p_idx,p_value); + Object*o = ObjectDB::get_instance(obj); + if (!o) + return; + + o->set(property,arr); +} + +bool ArrayPropertyEdit::_set(const StringName& p_name, const Variant& p_value){ + + String pn=p_name; + + if (pn.begins_with("array/")) { + + if (pn=="array/size") { + + Variant arr = get_array(); + int size = arr.call("size"); + + int newsize=p_value; + if (newsize==size) + return true; + + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action("Resize Array"); + ur->add_do_method(this,"_set_size",newsize); + ur->add_undo_method(this,"_set_size",size); + if (newsize<size) { + for(int i=newsize;i<size;i++) { + ur->add_undo_method(this,"_set_value",i,arr.get(i)); + + } + } + ur->add_do_method(this,"_notif_change"); + ur->add_undo_method(this,"_notif_change"); + ur->commit_action(); + return true; + } + if (pn=="array/page") { + page=p_value; + _change_notify(); + return true; + } + } else if (pn.begins_with("indices")) { + + if (pn.find("_")!=-1) { + //type + int idx=pn.get_slicec('/',1).get_slicec('_',0).to_int(); + + int type = p_value; + + Variant arr = get_array(); + + Variant value = arr.get(idx); + if (value.get_type()!=type && type>=0 && type<Variant::VARIANT_MAX) { + Variant::CallError ce; + Variant new_value=Variant::construct(Variant::Type(type),NULL,0,ce); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action("Change Array Value Type"); + ur->add_do_method(this,"_set_value",idx,new_value); + ur->add_undo_method(this,"_set_value",idx,value); + ur->add_do_method(this,"_notif_change"); + ur->add_undo_method(this,"_notif_change"); + ur->commit_action(); + + } + return true; + + } else { + int idx=pn.get_slicec('/',1).to_int(); + Variant arr = get_array(); + + Variant value = arr.get(idx); + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action("Change Array Value"); + ur->add_do_method(this,"_set_value",idx,p_value); + ur->add_undo_method(this,"_set_value",idx,value); + ur->add_do_method(this,"_notif_changev",p_name); + ur->add_undo_method(this,"_notif_changev",p_name); + ur->commit_action(); + return true; + } + } + + return false; +} + +bool ArrayPropertyEdit::_get(const StringName& p_name,Variant &r_ret) const { + + Variant arr = get_array(); + //int size = arr.call("size"); + + String pn=p_name; + if (pn.begins_with("array/")) { + + if (pn=="array/size") { + r_ret=arr.call("size"); + return true; + } + if (pn=="array/page") { + r_ret=page; + return true; + } + } else if (pn.begins_with("indices")) { + + if (pn.find("_")!=-1) { + //type + int idx=pn.get_slicec('/',1).get_slicec('_',0).to_int(); + bool valid; + r_ret=arr.get(idx,&valid); + if (valid) + r_ret=r_ret.get_type(); + return valid; + + } else { + int idx=pn.get_slicec('/',1).to_int(); + bool valid; + r_ret=arr.get(idx,&valid); + return valid; + } + } + + return false; +} + +void ArrayPropertyEdit::_get_property_list( List<PropertyInfo> *p_list) const{ + + Variant arr = get_array(); + int size = arr.call("size"); + + p_list->push_back( PropertyInfo(Variant::INT,"array/size",PROPERTY_HINT_RANGE,"0,100000,1") ); + int pages = size/ITEMS_PER_PAGE; + if (pages>0) + p_list->push_back( PropertyInfo(Variant::INT,"array/page",PROPERTY_HINT_RANGE,"0,"+itos(pages)+",1") ); + + int offset=page*ITEMS_PER_PAGE; + + int items=MIN(size-offset,ITEMS_PER_PAGE); + + + for(int i=0;i<items;i++) { + + Variant v=arr.get(i+offset); + if (arr.get_type()==Variant::ARRAY) { + p_list->push_back(PropertyInfo(Variant::INT,"indices/"+itos(i+offset)+"_type",PROPERTY_HINT_ENUM,vtypes)); + } + if (arr.get_type()!=Variant::ARRAY || v.get_type()!=Variant::NIL) { + PropertyInfo pi(v.get_type(),"indices/"+itos(i+offset)); + if (v.get_type()==Variant::OBJECT) { + pi.hint=PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string="Resource"; + } + p_list->push_back(pi); + } + } + +} + +void ArrayPropertyEdit::edit(Object* p_obj,const StringName& p_prop,Variant::Type p_deftype) { + + page=0; + property=p_prop; + obj=p_obj->get_instance_ID(); + default_type=p_deftype; + +} + +void ArrayPropertyEdit::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_set_size"),&ArrayPropertyEdit::_set_size); + ObjectTypeDB::bind_method(_MD("_set_value"),&ArrayPropertyEdit::_set_value); + ObjectTypeDB::bind_method(_MD("_notif_change"),&ArrayPropertyEdit::_notif_change); + ObjectTypeDB::bind_method(_MD("_notif_changev"),&ArrayPropertyEdit::_notif_changev); +} + +ArrayPropertyEdit::ArrayPropertyEdit() +{ + page=0; + for(int i=0;i<Variant::VARIANT_MAX;i++) { + + if (i>0) + vtypes+=","; + vtypes+=Variant::get_type_name( Variant::Type(i) ); + } + default_type=Variant::NIL; + +} diff --git a/tools/editor/array_property_edit.h b/tools/editor/array_property_edit.h new file mode 100644 index 0000000000..acfb8e68ed --- /dev/null +++ b/tools/editor/array_property_edit.h @@ -0,0 +1,36 @@ +#ifndef ARRAY_PROPERTY_EDIT_H +#define ARRAY_PROPERTY_EDIT_H + +#include "scene/main/node.h" + +class ArrayPropertyEdit : public Reference { + + OBJ_TYPE(ArrayPropertyEdit,Reference); + + int page; + ObjectID obj; + StringName property; + String vtypes; + Variant get_array() const; + Variant::Type default_type; + + void _notif_change(); + void _notif_changev(const String& p_v); + void _set_size(int p_size); + void _set_value(int p_idx,const Variant& p_value); + +protected: + + static void _bind_methods(); + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + +public: + + void edit(Object* p_obj, const StringName& p_prop, Variant::Type p_deftype); + + ArrayPropertyEdit(); +}; + +#endif // ARRAY_PROPERTY_EDIT_H diff --git a/tools/editor/dependency_editor.cpp b/tools/editor/dependency_editor.cpp new file mode 100644 index 0000000000..c04e82a08a --- /dev/null +++ b/tools/editor/dependency_editor.cpp @@ -0,0 +1,512 @@ +#include "dependency_editor.h" +#include "os/file_access.h" +#include "scene/gui/margin_container.h" +#include "io/resource_loader.h" +#include "editor_node.h" + +void DependencyEditor::_notification(int p_what){ + + +} + +void DependencyEditor::_searched(const String& p_path) { + + Map<String,String> dep_rename; + dep_rename[replacing]=p_path; + + + ResourceLoader::rename_dependencies(editing,dep_rename); + + _update_list(); + _update_file(); +} + +void DependencyEditor::_load_pressed(Object* p_item,int p_cell,int p_button){ + + TreeItem *ti=p_item->cast_to<TreeItem>(); + String fname = ti->get_text(0); + replacing = ti->get_text(1); + + search->set_title("Search Replacement For: "+replacing.get_file()); + + search->clear_filters(); + List<String> ext; + ResourceLoader::get_recognized_extensions_for_type(ti->get_metadata(0),&ext); + for (List<String>::Element *E=ext.front();E;E=E->next()) { + search->add_filter("*"+E->get()); + } + search->popup_centered_ratio(); + +} + +void DependencyEditor::_fix_and_find(EditorFileSystemDirectory *efsd, Map<String,Map<String,String> >& candidates){ + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fix_and_find(efsd->get_subdir(i),candidates); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + String file = efsd->get_file(i); + if (!candidates.has(file)) + continue; + + String path = efsd->get_file_path(i); + Map<String,String> &ss = candidates[file]; + + + for(Map<String,String>::Element *E=candidates[file].front();E;E=E->next()) { + + if (E->get()==String()) { + E->get()=path; + continue; + } + + //must match the best, using subdirs + String existing=E->get().replace_first("res://",""); + String current=path.replace_first("res://",""); + String lost=E->key().replace_first("res://",""); + + Vector<String> existingv=existing.split("/"); + existingv.invert(); + Vector<String> currentv=current.split("/"); + currentv.invert(); + Vector<String> lostv=lost.split("/"); + lostv.invert(); + + int existing_score=0; + int current_score=0; + + for(int j=0;j<lostv.size();j++) { + + if (j<existingv.size() && lostv[j]==existingv[j]) { + existing_score++; + } + if (j<currentv.size() && lostv[j]==currentv[j]) { + current_score++; + } + } + + if (current_score > existing_score) { + + //if it was the same, could track distance to new path but.. + + E->get()=path; //replace by more accurate + } + + } + + } + +} + + +void DependencyEditor::_fix_all(){ + + if (!EditorFileSystem::get_singleton()->get_filesystem()) + return; + + Map<String,Map<String,String> > candidates; + + for (List<String>::Element *E=missing.front();E;E=E->next()) { + + String base = E->get().get_file(); + if (!candidates.has(base)) { + candidates[base]=Map<String,String>(); + } + + candidates[base][E->get()]=""; + } + + _fix_and_find(EditorFileSystem::get_singleton()->get_filesystem(),candidates); + + Map<String,String> remaps; + + for (Map<String,Map<String,String> >::Element *E=candidates.front();E;E=E->next()) { + + for (Map<String,String>::Element *F=E->get().front();F;F=F->next()) { + + if (F->get()!=String()) { + remaps[F->key()]=F->get(); + } + } + + } + + if (remaps.size()) { + + ResourceLoader::rename_dependencies(editing,remaps); + + _update_list(); + _update_file(); + } +} + +void DependencyEditor::_update_file() { + + EditorFileSystem::get_singleton()->update_file(editing); + +} + +void DependencyEditor::_update_list() { + + List<String> deps; + ResourceLoader::get_dependencies(editing,&deps,true); + + tree->clear(); + missing.clear(); + + TreeItem *root = tree->create_item(); + + Ref<Texture> folder = get_icon("folder","FileDialog"); + + bool broken=false; + + for(List<String>::Element *E=deps.front();E;E=E->next()) { + + TreeItem *item = tree->create_item(root); + + String n = E->get(); + String path; + String type; + + if (n.find("::")!=-1) { + path = n.get_slice("::",0); + type = n.get_slice("::",1); + } else { + path=n; + type="Resource"; + } + String name = path.get_file(); + + Ref<Texture> icon; + if (has_icon(type,"EditorIcons")) { + icon=get_icon(type,"EditorIcons"); + } else { + icon=get_icon("Object","EditorIcons"); + } + item->set_text(0,name); + item->set_icon(0,icon); + item->set_metadata(0,type); + item->set_text(1,path); + + if (!FileAccess::exists(path)) { + item->set_custom_color(1,Color(1,0.4,0.3)); + missing.push_back(path); + broken=true; + } + + item->add_button(1,folder,0); + } + + fixdeps->set_disabled(!broken); + +} + + + +void DependencyEditor::edit(const String& p_path) { + + + editing=p_path; + set_title("Dependencies For: "+p_path.get_file()); + + _update_list(); + popup_centered_ratio(); + + if (EditorNode::get_singleton()->is_scene_open(p_path)) { + EditorNode::get_singleton()->show_warning("Scene '"+p_path.get_file()+"' is currently being edited.\nChanges will not take effect unless reloaded."); + } else if (ResourceCache::has(p_path)) { + EditorNode::get_singleton()->show_warning("Resource '"+p_path.get_file()+"' is in use.\nChanges will take effect when reloaded."); + } +} + + +void DependencyEditor::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_searched"),&DependencyEditor::_searched); + ObjectTypeDB::bind_method(_MD("_load_pressed"),&DependencyEditor::_load_pressed); + ObjectTypeDB::bind_method(_MD("_fix_all"),&DependencyEditor::_fix_all); + +} + +DependencyEditor::DependencyEditor() { + + VBoxContainer *vb = memnew( VBoxContainer ); + vb->set_name("Dependencies"); + add_child(vb); + set_child_rect(vb); + + tree = memnew( Tree ); + tree->set_columns(2); + tree->set_column_titles_visible(true); + tree->set_column_title(0,"Resource"); + tree->set_column_title(1,"Path"); + tree->set_hide_root(true); + tree->connect("button_pressed",this,"_load_pressed"); + + HBoxContainer *hbc = memnew( HBoxContainer ); + Label *label = memnew( Label("Dependencies:")); + hbc->add_child(label); + hbc->add_spacer(); + fixdeps = memnew( Button("Fix Broken")); + hbc->add_child(fixdeps); + fixdeps->connect("pressed",this,"_fix_all"); + + vb->add_child(hbc); + + MarginContainer *mc = memnew( MarginContainer ); + mc->set_v_size_flags(SIZE_EXPAND_FILL); + + mc->add_child(tree); + vb->add_child(mc); + + set_title("Dependency Editor"); + search = memnew( EditorFileDialog ); + search->connect("file_selected",this,"_searched"); + search->set_mode(EditorFileDialog::MODE_OPEN_FILE); + search->set_title("Search Replacement Resource:"); + add_child(search); + +} + +///////////////////////////////////// + + + +void DependencyEditorOwners::_fill_owners(EditorFileSystemDirectory *efsd) { + + if (!efsd) + return; + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fill_owners(efsd->get_subdir(i)); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + Vector<String> deps = efsd->get_file_deps(i); + //print_line(":::"+efsd->get_file_path(i)); + bool found=false; + for(int j=0;j<deps.size();j++) { + //print_line("\t"+deps[j]+" vs "+editing); + if (deps[j]==editing) { + //print_line("found"); + found=true; + break; + } + } + if (!found) + continue; + + Ref<Texture> icon; + String type=efsd->get_file_type(i); + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + owners->add_item(efsd->get_file_path(i),icon); + } + +} + +void DependencyEditorOwners::show(const String& p_path) { + + editing=p_path; + owners->clear(); + _fill_owners(EditorFileSystem::get_singleton()->get_filesystem()); + popup_centered_ratio(); + + set_title("Owners Of: "+p_path.get_file()); + +} + +DependencyEditorOwners::DependencyEditorOwners() { + + + owners = memnew( ItemList ); + add_child(owners); + set_child_rect(owners); + + +} + +/////////////////////// + + +void DependencyRemoveDialog::_fill_owners(EditorFileSystemDirectory *efsd) { + + if (!efsd) + return; + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fill_owners(efsd->get_subdir(i)); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + Vector<String> deps = efsd->get_file_deps(i); + //print_line(":::"+efsd->get_file_path(i)); + Set<String> met; + for(int j=0;j<deps.size();j++) { + if (files.has(deps[j])) { + met.insert(deps[j]); + } + } + if (!met.size()) + continue; + + exist=true; + + Ref<Texture> icon; + String type=efsd->get_file_type(i); + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + + for(Set<String>::Element *E=met.front();E;E=E->next()) { + + String which = E->get(); + if (!files[which]) { + TreeItem *ti=owners->create_item(owners->get_root()); + ti->set_text(0,which.get_file()); + files[which]=ti; + + } + TreeItem *ti=owners->create_item(files[which]); + ti->set_text(0,efsd->get_file_path(i)); + ti->set_icon(0,icon); + } + + } + +} + +void DependencyRemoveDialog::show(const Vector<String> &to_erase) { + + exist=false; + owners->clear(); + files.clear(); + TreeItem *root=owners->create_item(); + for(int i=0;i<to_erase.size();i++) { + files[to_erase[i]]=NULL; + } + + _fill_owners(EditorFileSystem::get_singleton()->get_filesystem()); + + if (exist) { + owners->show(); + text->set_text("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)"); + popup_centered_minsize(Size2(500,220)); + } else { + owners->hide(); + text->set_text("Remove selected files from the project? (no undo)"); + popup_centered_minsize(Size2(400,100)); + } + +} + +void DependencyRemoveDialog::ok_pressed() { + + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + for (Map<String,TreeItem*>::Element *E=files.front();E;E=E->next()) { + + da->remove(E->key()); + EditorFileSystem::get_singleton()->update_file(E->key()); + } + memdelete(da); + +} + +DependencyRemoveDialog::DependencyRemoveDialog() { + + VBoxContainer *vb = memnew( VBoxContainer ); + add_child(vb); + set_child_rect(vb); + + text = memnew( Label ); + vb->add_child(text); + + owners = memnew( Tree ); + owners->set_hide_root(true); + vb->add_child(owners); + owners->set_v_size_flags(SIZE_EXPAND_FILL); + get_ok()->set_text("Remove"); +} + + +////////////// + + +void DependencyErrorDialog::show(const String& p_for_file,const Vector<String> &report) { + + + for_file=p_for_file; + set_title("Error loading: "+p_for_file.get_file()); + files->clear(); + + TreeItem *root = files->create_item(NULL); + for(int i=0;i<report.size();i++) { + + String dep; + String type="Object"; + dep=report[i].get_slice("::",0); + if (report[i].get_slice_count("::")>0) + type=report[i].get_slice("::",1); + + Ref<Texture> icon; + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + TreeItem *ti=files->create_item(root); + ti->set_text(0,dep); + ti->set_icon(0,icon); + + } + + popup_centered_minsize(Size2(500,220)); + +} + +void DependencyErrorDialog::ok_pressed() { + + EditorNode::get_singleton()->load_scene(for_file,true); +} + +void DependencyErrorDialog::custom_action(const String&) { + + EditorNode::get_singleton()->fix_dependencies(for_file); +} + +DependencyErrorDialog::DependencyErrorDialog() { + + VBoxContainer *vb = memnew( VBoxContainer ); + add_child(vb); + set_child_rect(vb); + + + files = memnew( Tree ); + files->set_hide_root(true); + vb->add_margin_child("Scene failed to load due to missing dependencies:",files,true); + files->set_v_size_flags(SIZE_EXPAND_FILL); + get_ok()->set_text("Open Anyway"); + + text = memnew( Label ); + vb->add_child(text); + text->set_text("Which action should be taken?"); + + + fdep=add_button("Fix Dependencies",true,"fixdeps"); + + set_title("Errors loading!"); + +} diff --git a/tools/editor/dependency_editor.h b/tools/editor/dependency_editor.h new file mode 100644 index 0000000000..1c328e7a93 --- /dev/null +++ b/tools/editor/dependency_editor.h @@ -0,0 +1,94 @@ +#ifndef DEPENDENCY_EDITOR_H +#define DEPENDENCY_EDITOR_H + +#include "scene/gui/dialogs.h" +#include "scene/gui/tree.h" +#include "scene/gui/tab_container.h" +#include "editor_file_dialog.h" + +class EditorFileSystemDirectory; + +class DependencyEditor : public AcceptDialog { + OBJ_TYPE(DependencyEditor,AcceptDialog); + + + Tree *tree; + Button *fixdeps; + + EditorFileDialog *search; + + String replacing; + String editing; + List<String> missing; + + + void _fix_and_find(EditorFileSystemDirectory *efsd, Map<String,Map<String,String> >& candidates); + + void _searched(const String& p_path); + void _load_pressed(Object* p_item,int p_cell,int p_button); + void _fix_all(); + void _update_list(); + + void _update_file(); + +protected: + + static void _bind_methods(); + void _notification(int p_what); +public: + + + void edit(const String& p_path); + DependencyEditor(); +}; + +class DependencyEditorOwners : public AcceptDialog { + OBJ_TYPE(DependencyEditorOwners,AcceptDialog); + + ItemList *owners; + String editing; + void _fill_owners(EditorFileSystemDirectory *efsd); + +public: + + void show(const String& p_path); + DependencyEditorOwners(); +}; + +class DependencyRemoveDialog : public ConfirmationDialog { + OBJ_TYPE(DependencyRemoveDialog,ConfirmationDialog); + + + Label *text; + Tree *owners; + bool exist; + Map<String,TreeItem*> files; + void _fill_owners(EditorFileSystemDirectory *efsd); + + void ok_pressed(); + +public: + + void show(const Vector<String> &to_erase); + DependencyRemoveDialog(); +}; + + +class DependencyErrorDialog : public ConfirmationDialog { + OBJ_TYPE(DependencyErrorDialog,ConfirmationDialog); + + + String for_file; + Button *fdep; + Label *text; + Tree *files; + void ok_pressed(); + void custom_action(const String&); + +public: + + void show(const String& p_for,const Vector<String> &report); + DependencyErrorDialog(); +}; + +#endif // DEPENDENCY_EDITOR_H diff --git a/tools/editor/editor_data.cpp b/tools/editor/editor_data.cpp index 7f42f19a9b..673ee30adb 100644 --- a/tools/editor/editor_data.cpp +++ b/tools/editor/editor_data.cpp @@ -39,7 +39,7 @@ void EditorHistory::_cleanup_history() { bool fail=false; for(int j=0;j<history[i].path.size();j++) { - if (!history[i].path[j].res.is_null()) + if (!history[i].path[j].ref.is_null()) continue; if (ObjectDB::get_instance(history[i].path[j].object)) @@ -70,10 +70,10 @@ void EditorHistory::_add_object(ObjectID p_object,const String& p_property,int p Object *obj = ObjectDB::get_instance(p_object); ERR_FAIL_COND(!obj); - Resource *r = obj->cast_to<Resource>(); + Reference *r = obj->cast_to<Reference>(); Obj o; if (r) - o.res=RES(r); + o.ref=REF(r); o.object=p_object; o.property=p_property; @@ -123,6 +123,27 @@ void EditorHistory::add_object(ObjectID p_object,int p_relevel){ _add_object(p_object,"",p_relevel); } +int EditorHistory::get_history_len() { + return history.size(); +} +int EditorHistory::get_history_pos() { + return current; +} + +ObjectID EditorHistory::get_history_obj(int p_obj) const { + ERR_FAIL_INDEX_V(p_obj,history.size(),0); + ERR_FAIL_INDEX_V(history[p_obj].level,history[p_obj].path.size(),0); + return history[p_obj].path[history[p_obj].level].object; +} + +bool EditorHistory::is_at_begining() const { + return current<=0; +} +bool EditorHistory::is_at_end() const { + + return ((current+1)>=history.size()); +} + bool EditorHistory::next() { @@ -523,7 +544,7 @@ Ref<Script> EditorData::get_scene_root_script(int p_idx) const { if (!edited_scene[p_idx].root) return Ref<Script>(); Ref<Script> s=edited_scene[p_idx].root->get_script(); - if (!s.is_valid()) { + if (!s.is_valid() && edited_scene[p_idx].root->get_child_count()) { Node *n = edited_scene[p_idx].root->get_child(0); while(!s.is_valid() && n && n->get_filename()==String()) { s=n->get_script(); diff --git a/tools/editor/editor_data.h b/tools/editor/editor_data.h index cbec2295f6..c5ee83ae63 100644 --- a/tools/editor/editor_data.h +++ b/tools/editor/editor_data.h @@ -45,7 +45,7 @@ class EditorHistory { struct Obj { - RES res; + REF ref; ObjectID object; String property; }; @@ -75,10 +75,17 @@ friend class EditorData; public: + bool is_at_begining() const; + bool is_at_end() const; + void add_object(ObjectID p_object); void add_object(ObjectID p_object,const String& p_subprop); void add_object(ObjectID p_object,int p_relevel); + int get_history_len(); + int get_history_pos(); + ObjectID get_history_obj(int p_obj) const; + bool next(); bool previous(); ObjectID get_current(); diff --git a/tools/editor/editor_file_dialog.cpp b/tools/editor/editor_file_dialog.cpp index b1bbd71f7b..c62347d129 100644 --- a/tools/editor/editor_file_dialog.cpp +++ b/tools/editor/editor_file_dialog.cpp @@ -190,7 +190,7 @@ void EditorFileDialog::_thumbnail_done(const String& p_path,const Ref<Texture>& void EditorFileDialog::_request_single_thumbnail(const String& p_path) { EditorResourcePreview::get_singleton()->queue_resource_preview(p_path,this,"_thumbnail_done",p_path); - print_line("want file "+p_path); + //print_line("want file "+p_path); set_process(true); preview_waiting=true; preview_wheel_timeout=0; @@ -359,7 +359,7 @@ void EditorFileDialog::_item_dc_selected(int p_item) { if (d["dir"]) { - print_line("change dir: "+String(d["name"])); + //print_line("change dir: "+String(d["name"])); dir_access->change_dir(d["name"]); if (mode==MODE_OPEN_FILE || mode==MODE_OPEN_FILES || mode==MODE_OPEN_DIR) file->set_text(""); @@ -536,6 +536,7 @@ void EditorFileDialog::update_file_list() { if (get_icon_func) { + Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get())); //ti->set_icon(0,icon); if (display_mode==DISPLAY_THUMBNAILS) { diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp index d741087a9f..33e4a15c85 100644 --- a/tools/editor/editor_file_system.cpp +++ b/tools/editor/editor_file_system.cpp @@ -94,6 +94,12 @@ bool EditorFileSystemDirectory::get_file_meta(int p_idx) const { return files[p_idx].meta.enabled; } +Vector<String> EditorFileSystemDirectory::get_file_deps(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>()); + return files[p_idx].meta.deps; + +} Vector<String> EditorFileSystemDirectory::get_missing_sources(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>()); @@ -118,7 +124,7 @@ bool EditorFileSystemDirectory::is_missing_sources(int p_idx) const { return false; } -String EditorFileSystemDirectory::get_file_type(int p_idx) const { +StringName EditorFileSystemDirectory::get_file_type(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),""); return files[p_idx].type; @@ -198,6 +204,13 @@ EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String& } m.import_editor=imd->get_editor(); } + + List<String> deps; + ResourceLoader::get_dependencies(p_path,&deps); + for(List<String>::Element *E=deps.front();E;E=E->next()) { + m.deps.push_back(E->get()); + } + return m; } @@ -358,7 +371,7 @@ void EditorFileSystem::_scan_scenes() { String project=Globals::get_singleton()->get_resource_path(); - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("file_cache"); + String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache"); FileAccess *f =FileAccess::open(fscache,FileAccess::READ); if (f) { @@ -397,7 +410,7 @@ void EditorFileSystem::_scan_scenes() { } else { Vector<String> split = l.split("::"); - ERR_CONTINUE( split.size() != 4); + ERR_CONTINUE( split.size() != 5); String name = split[0]; String file; @@ -429,6 +442,15 @@ void EditorFileSystem::_scan_scenes() { } } + String deps = split[4].strip_edges(); + if (deps.length()) { + Vector<String> dp = deps.split("<>"); + for(int i=0;i<dp.size();i++) { + String path=dp[i]; + fc.meta.deps.push_back(path); + } + } + file_cache[name]=fc; ERR_CONTINUE(!dc); @@ -530,6 +552,7 @@ void EditorFileSystem::scan() { thread = Thread::create(_thread_func,this,s); //tree->hide(); //progress->show(); + } @@ -798,6 +821,14 @@ void EditorFileSystem::_save_type_cache_fs(DirItem *p_dir,FileAccess *p_file) { } } + s+="::"; + for(int j=0;j<p_dir->files[i]->meta.deps.size();j++) { + + if (j>0) + s+="<>"; + s+=p_dir->files[i]->meta.deps[j]; + } + p_file->store_line(s); } @@ -1037,6 +1068,13 @@ void EditorFileSystem::update_file(const String& p_file) { return; } + if (!FileAccess::exists(p_file)) { + //was removed + fs->files.remove(cpos); + call_deferred("emit_signal","filesystem_changed"); //update later + return; + + } String type = ResourceLoader::get_resource_type(p_file); diff --git a/tools/editor/editor_file_system.h b/tools/editor/editor_file_system.h index 3f413292fe..f79dd209ef 100644 --- a/tools/editor/editor_file_system.h +++ b/tools/editor/editor_file_system.h @@ -59,13 +59,14 @@ class EditorFileSystemDirectory : public Object { Vector<Source> sources; String import_editor; + Vector<String> deps; bool enabled; }; struct FileInfo { String file; - String type; + StringName type; uint64_t modified_time; ImportMeta meta; @@ -87,10 +88,11 @@ public: int get_file_count() const; String get_file(int p_idx) const; String get_file_path(int p_idx) const; - String get_file_type(int p_idx) const; + StringName get_file_type(int p_idx) const; bool get_file_meta(int p_idx) const; bool is_missing_sources(int p_idx) const; Vector<String> get_missing_sources(int p_idx) const; + Vector<String> get_file_deps(int p_idx) const; EditorFileSystemDirectory *get_parent(); @@ -120,7 +122,7 @@ class EditorFileSystem : public Node { String path; String name; Vector<DirItem*> dirs; - Vector<SceneItem*> files; + Vector<SceneItem*> files; ~DirItem(); }; @@ -149,6 +151,7 @@ class EditorFileSystem : public Node { String type; uint64_t modification_time; EditorFileSystemDirectory::ImportMeta meta; + Vector<String> deps; }; struct DirCache { diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp index b28b349c86..84fc14d2ec 100644 --- a/tools/editor/editor_import_export.cpp +++ b/tools/editor/editor_import_export.cpp @@ -255,7 +255,16 @@ static void _add_filter_to_list(Set<StringName>& r_list,const String& p_filter) } +Vector<uint8_t> EditorExportPlatform::get_exported_file_default(String& p_fname) const { + FileAccess *f = FileAccess::open(p_fname,FileAccess::READ); + ERR_FAIL_COND_V(!f,Vector<uint8_t>()); + Vector<uint8_t> ret; + ret.resize(f->get_len()); + int rbs = f->get_buffer(ret.ptr(),ret.size()); + memdelete(f); + return ret; +} Vector<uint8_t> EditorExportPlatform::get_exported_file(String& p_fname) const { @@ -270,13 +279,9 @@ Vector<uint8_t> EditorExportPlatform::get_exported_file(String& p_fname) const { } - FileAccess *f = FileAccess::open(p_fname,FileAccess::READ); - ERR_FAIL_COND_V(!f,Vector<uint8_t>()); - Vector<uint8_t> ret; - ret.resize(f->get_len()); - int rbs = f->get_buffer(ret.ptr(),ret.size()); - memdelete(f); - return ret; + return get_exported_file_default(p_fname); + + } Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const { @@ -557,6 +562,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func group_shrink*=EditorImportExport::get_singleton()->get_export_image_shrink(); switch(EditorImportExport::get_singleton()->image_export_group_get_image_action(E->get())) { + case EditorImportExport::IMAGE_ACTION_KEEP: case EditorImportExport::IMAGE_ACTION_NONE: { switch(EditorImportExport::get_singleton()->get_export_image_action()) { @@ -581,7 +587,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func } break; //use default case EditorImportExport::IMAGE_ACTION_COMPRESS_RAM: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM; - } break; //use default + } break; //use default } String image_list_md5; @@ -825,13 +831,32 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func StringName engine_cfg="res://engine.cfg"; + StringName boot_splash; + { + String splash=Globals::get_singleton()->get("application/boot_splash"); //avoid splash from being converted + splash=splash.strip_edges(); + if (splash!=String()) { + if (!splash.begins_with("res://")) + splash="res://"+splash; + splash=splash.simplify_path(); + boot_splash=splash; + } + } + + + for(int i=0;i<files.size();i++) { if (remap_files.has(files[i]) || files[i]==engine_cfg) //gonna be remapped (happened before!) continue; //from atlas? String src=files[i]; - Vector<uint8_t> buf = get_exported_file(src); + Vector<uint8_t> buf; + + if (src==boot_splash) + buf = get_exported_file_default(src); //bootsplash must be kept if used + else + buf = get_exported_file(src); ERR_CONTINUE( saved.has(src) ); @@ -1608,6 +1633,8 @@ void EditorImportExport::load_config() { g.action=IMAGE_ACTION_COMPRESS_RAM; else if (action=="compress_disk") g.action=IMAGE_ACTION_COMPRESS_DISK; + else if (action=="keep") + g.action=IMAGE_ACTION_KEEP; } if (d.has("atlas")) @@ -1735,6 +1762,7 @@ void EditorImportExport::save_config() { case IMAGE_ACTION_NONE: d["action"]="default"; break; case IMAGE_ACTION_COMPRESS_RAM: d["action"]="compress_ram"; break; case IMAGE_ACTION_COMPRESS_DISK: d["action"]="compress_disk"; break; + case IMAGE_ACTION_KEEP: d["action"]="keep"; break; } diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h index f134a479a4..d8601929cf 100644 --- a/tools/editor/editor_import_export.h +++ b/tools/editor/editor_import_export.h @@ -83,6 +83,7 @@ public: typedef Error (*EditorExportSaveFunction)(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total); protected: + Vector<uint8_t> get_exported_file_default(String& p_fname) const; virtual Vector<uint8_t> get_exported_file(String& p_fname) const; virtual Vector<StringName> get_dependencies(bool p_bundles) const; @@ -227,6 +228,8 @@ public: IMAGE_ACTION_NONE, IMAGE_ACTION_COMPRESS_DISK, IMAGE_ACTION_COMPRESS_RAM, + IMAGE_ACTION_KEEP //for group + }; enum ScriptAction { diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index b0a2c568de..63684dcc93 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -93,7 +93,7 @@ #include "plugins/light_occluder_2d_editor_plugin.h" #include "plugins/color_ramp_editor_plugin.h" #include "plugins/collision_shape_2d_editor_plugin.h" - +#include "os/input.h" // end #include "tools/editor/io_plugins/editor_texture_import_plugin.h" #include "tools/editor/io_plugins/editor_scene_import_plugin.h" @@ -459,17 +459,74 @@ void EditorNode::open_resource(const String& p_type) { current_option=RESOURCE_LOAD; } -void EditorNode::save_resource(const Ref<Resource>& p_resource) { +void EditorNode::save_resource_in_path(const Ref<Resource>& p_resource,const String& p_path) { - ERR_FAIL_COND(p_resource.is_null() || p_resource->get_path()=="" || p_resource->get_path().find("::")!=-1); - resources_dock->save_resource(p_resource->get_path(),p_resource); + editor_data.apply_changes_in_editors(); + int flg=0; + if (EditorSettings::get_singleton()->get("on_save/compress_binary_resources")) + flg|=ResourceSaver::FLAG_COMPRESS; + if (EditorSettings::get_singleton()->get("on_save/save_paths_as_relative")) + flg|=ResourceSaver::FLAG_RELATIVE_PATHS; + + String path = Globals::get_singleton()->localize_path(p_path); + Error err = ResourceSaver::save(path,p_resource,flg|ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); + + if (err!=OK) { + accept->set_text("Error saving resource!"); + accept->popup_centered_minsize(); + return; + } +// EditorFileSystem::get_singleton()->update_file(path,p_resource->get_type()); + + ((Resource*)p_resource.ptr())->set_path(path); + emit_signal("resource_saved",p_resource); + +} + +void EditorNode::save_resource(const Ref<Resource>& p_resource) { + + if (p_resource->get_path().is_resource_file()) { + save_resource_in_path(p_resource,p_resource->get_path()); + } else { + save_resource_as(p_resource); + } } void EditorNode::save_resource_as(const Ref<Resource>& p_resource) { - resources_dock->save_resource_as(p_resource); + file->set_mode(EditorFileDialog::MODE_SAVE_FILE); + bool relpaths = (p_resource->has_meta("__editor_relpaths__") && p_resource->get_meta("__editor_relpaths__").operator bool()); + + List<String> extensions; + Ref<PackedScene> sd = memnew( PackedScene ); + ResourceSaver::get_recognized_extensions(p_resource,&extensions); + file->clear_filters(); + for(int i=0;i<extensions.size();i++) { + + file->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper()); + } + //file->set_current_path(current_path); + 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(); + if (extensions.find(ext)==NULL) { + file->set_current_path(p_resource->get_path().replacen("."+ext,"."+extensions.front()->get())); + } + } + } else { + + String existing; + if (extensions.size()) { + existing="new_"+p_resource->get_type().to_lower()+"."+extensions.front()->get().to_lower(); + } + file->set_current_path(existing); + + } + file->popup_centered_ratio(); + file->set_title("Save Resource As.."); } @@ -1049,7 +1106,7 @@ void EditorNode::_dialog_action(String p_file) { push_item(res.operator->() ); - } break; + } break; case FILE_OPEN_SCENE: { @@ -1320,7 +1377,20 @@ void EditorNode::_dialog_action(String p_file) { unzClose(pkg); } break; + case RESOURCE_SAVE: + case RESOURCE_SAVE_AS: { + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + + save_resource_in_path(current_res,p_file); + + } break; default: { //save scene? @@ -1358,6 +1428,67 @@ void EditorNode::push_item(Object *p_object,const String& p_property) { } +void EditorNode::_select_history(int p_idx) { + + //push it to the top, it is not correct, but it's more useful + ObjectID id=editor_history.get_history_obj(p_idx); + Object* obj=ObjectDB::get_instance(id); + if (!obj) + return; + push_item(obj); +} + +void EditorNode::_prepare_history() { + + int history_to = MAX(0,editor_history.get_history_len()-25); + + editor_history_menu->get_popup()->clear(); + + Ref<Texture> base_icon = gui_base->get_icon("Object","EditorIcons"); + Set<ObjectID> already; + for(int i=editor_history.get_history_len()-1;i>=history_to;i--) { + + + ObjectID id=editor_history.get_history_obj(i); + Object* obj=ObjectDB::get_instance(id); + if (!obj || already.has(id)) { + if (history_to>0) { + history_to--; + } + continue; + } + + already.insert(id); + + Ref<Texture> icon = gui_base->get_icon("Object","EditorIcons"); + if (gui_base->has_icon(obj->get_type(),"EditorIcons")) + icon=gui_base->get_icon(obj->get_type(),"EditorIcons"); + else + icon=base_icon; + + String text; + if (obj->cast_to<Resource>()) { + Resource *r=obj->cast_to<Resource>(); + if (r->get_path().is_resource_file()) + text=r->get_path().get_file(); + else if (r->get_name()!=String()) { + text=r->get_name(); + } else { + text=r->get_type(); + } + } else if (obj->cast_to<Node>()) { + text=obj->cast_to<Node>()->get_name(); + } else { + text=obj->get_type(); + } + + if (i==editor_history.get_history_pos()) { + text="["+text+"]"; + } + editor_history_menu->get_popup()->add_icon_item(icon,text,i); + } +} + void EditorNode::_property_editor_forward() { if (editor_history.next()) @@ -1402,6 +1533,9 @@ void EditorNode::_edit_current() { uint32_t current = editor_history.get_current(); Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + property_back->set_disabled( editor_history.is_at_begining() ); + property_forward->set_disabled( editor_history.is_at_end() ); + this->current=current_obj; editor_path->update_path(); @@ -1416,7 +1550,10 @@ void EditorNode::_edit_current() { object_menu->set_disabled(true); - if (current_obj->is_type("Resource")) { + bool is_resource = current_obj->is_type("Resource"); + resource_save_button->set_disabled(!is_resource); + + if (is_resource) { Resource *current_res = current_obj->cast_to<Resource>(); @@ -1425,12 +1562,11 @@ void EditorNode::_edit_current() { property_editor->edit( current_res ); object_menu->set_disabled(false); - resources_dock->add_resource(Ref<Resource>(current_res)); - //top_pallete->set_current_tab(1); - } + //resources_dock->add_resource(Ref<Resource>(current_res)); - if (current_obj->is_type("Node")) { + //top_pallete->set_current_tab(1); + } else if (current_obj->is_type("Node")) { Node * current_node = current_obj->cast_to<Node>(); ERR_FAIL_COND(!current_node); @@ -1445,6 +1581,12 @@ void EditorNode::_edit_current() { //top_pallete->set_current_tab(0); + } else { + + property_editor->edit( current_obj ); + //scene_tree_dock->set_selected(current_node); + //object_menu->get_popup()->clear(); + } /* Take care of PLUGIN EDITOR */ @@ -1517,7 +1659,13 @@ void EditorNode::_edit_current() { p->add_item("Copy Params",OBJECT_COPY_PARAMS); p->add_item("Set Params",OBJECT_PASTE_PARAMS); p->add_separator(); - p->add_item("Make Resources Unique",OBJECT_UNIQUE_RESOURCES); + p->add_item("Paste Resource",RESOURCE_PASTE); + if (is_resource) { + p->add_item("Copy Resource",RESOURCE_COPY); + p->add_item("Make Built-In",RESOURCE_UNREF); + } + p->add_separator(); + p->add_item("Make Sub-Resources Unique",OBJECT_UNIQUE_RESOURCES); p->add_separator(); p->add_icon_item(gui_base->get_icon("Help","EditorIcons"),"Class Reference",OBJECT_REQUEST_HELP); List<MethodInfo> methods; @@ -1550,6 +1698,20 @@ void EditorNode::_edit_current() { _update_keying(); } +void EditorNode::_resource_created() { + + Object *c = create_dialog->instance_selected(); + + ERR_FAIL_COND(!c); + Resource *r = c->cast_to<Resource>(); + ERR_FAIL_COND(!r); + + REF res( r ); + + push_item(c); + +} + void EditorNode::_resource_selected(const RES& p_res,const String& p_property) { @@ -1762,6 +1924,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { int idx = editor_data.add_edited_scene(-1); _scene_tab_changed(idx); + editor_data.clear_editor_states(); //_cleanup_scene(); @@ -1804,6 +1967,13 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { quick_open->set_title("Quick Open Script.."); } break; + case FILE_QUICK_OPEN_FILE: { + + + quick_open->popup("Resource",false,true); + quick_open->set_title("Quick Search File.."); + + } break; case FILE_RUN_SCRIPT: { file_script->popup_centered_ratio(); @@ -2266,7 +2436,70 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { } break; #endif - + case RESOURCE_NEW: { + + create_dialog->popup_centered_ratio(); + } break; + case RESOURCE_LOAD: { + + open_resource(); + } break; + case RESOURCE_SAVE: { + + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + + save_resource(current_res); + + } break; + case RESOURCE_SAVE_AS: { + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + + save_resource_as(current_res); + + } break; + case RESOURCE_UNREF: { + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + current_res->set_path(""); + _edit_current(); + } break; + case RESOURCE_COPY: { + + uint32_t current = editor_history.get_current(); + Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!current_obj->cast_to<Resource>()) + + RES current_res = RES(current_obj->cast_to<Resource>()); + + EditorSettings::get_singleton()->set_resource_clipboard(current_res); + + } break; + case RESOURCE_PASTE: { + + RES r = EditorSettings::get_singleton()->get_resource_clipboard(); + if (r.is_valid()) { + push_item(EditorSettings::get_singleton()->get_resource_clipboard().ptr(),String()); + } + + } break; case OBJECT_REQUEST_HELP: { if (current) { @@ -3050,7 +3283,21 @@ void EditorNode::set_current_scene(int p_idx) { } -Error EditorNode::load_scene(const String& p_scene) { +bool EditorNode::is_scene_open(const String& p_path) { + + for(int i=0;i<editor_data.get_edited_scene_count();i++) { + if (editor_data.get_scene_path(i)==p_path) + return true; + } + + return false; +} + +void EditorNode::fix_dependencies(const String& p_for_file) { + dependency_fixer->edit(p_for_file); +} + +Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) { if (!is_inside_tree()) { defer_load_scene = p_scene; @@ -3096,6 +3343,8 @@ Error EditorNode::load_scene(const String& p_scene) { //_cleanup_scene(); // i'm sorry but this MUST happen to avoid modified resources to not be reloaded. + dependency_errors.clear(); + Ref<PackedScene> sdata = ResourceLoader::load(lpath,"",true); if (!sdata.is_valid()) { @@ -3113,6 +3362,35 @@ Error EditorNode::load_scene(const String& p_scene) { return ERR_FILE_NOT_FOUND; } + if (!p_ignore_broken_deps && dependency_errors.has(lpath)) { + + current_option=-1; + Vector<String> errors; + for(Set<String>::Element *E=dependency_errors[lpath].front();E;E=E->next()) { + + errors.push_back(E->get()); + } + dependency_error->show(lpath,errors); + opening_prev=false; + + if (prev!=-1) { + set_current_scene(prev); + editor_data.remove_scene(idx); + } + return ERR_FILE_MISSING_DEPENDENCIES; + } + + dependency_errors.erase(lpath); //at least not self path + + for (Map<String,Set<String> >::Element *E=dependency_errors.front();E;E=E->next()) { + + String txt="Scene '"+E->key()+"' has broken dependencies:\n"; + for(Set<String>::Element *F=E->get().front();F;F=F->next()) { + txt+="\t"+F->get()+"\n"; + } + add_io_error(txt); + } + sdata->set_path(lpath,true); //take over path Node*new_scene=sdata->instance(true); @@ -3408,9 +3686,12 @@ void EditorNode::hide_animation_player_editors() { void EditorNode::_quick_opened(const String& p_resource) { - print_line("quick_opened"); - if (quick_open->get_base_type()=="PackedScene") { + if (current_option==FILE_QUICK_OPEN_FILE) { + scenes_dock->open(p_resource); + return; + } + if (quick_open->get_base_type()=="PackedScene") { open_request(p_resource); } else { load_resource(p_resource); @@ -3595,6 +3876,8 @@ void EditorNode::_bind_methods() { ObjectTypeDB::bind_method("_quick_opened",&EditorNode::_quick_opened); ObjectTypeDB::bind_method("_quick_run",&EditorNode::_quick_run); + ObjectTypeDB::bind_method("_resource_created",&EditorNode::_resource_created); + ObjectTypeDB::bind_method("_import_action",&EditorNode::_import_action); //ObjectTypeDB::bind_method("_import",&EditorNode::_import); // ObjectTypeDB::bind_method("_import_conflicts_solved",&EditorNode::_import_conflicts_solved); @@ -3624,6 +3907,8 @@ void EditorNode::_bind_methods() { ObjectTypeDB::bind_method("_set_main_scene_state",&EditorNode::_set_main_scene_state); ObjectTypeDB::bind_method("_update_scene_tabs",&EditorNode::_update_scene_tabs); + ObjectTypeDB::bind_method("_prepare_history",&EditorNode::_prepare_history); + ObjectTypeDB::bind_method("_select_history",&EditorNode::_select_history); ObjectTypeDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin); @@ -4105,6 +4390,14 @@ EditorNode::EditorNode() { EditorHelp::generate_doc(); //before any editor classes are crated + if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) { + //only if no touchscreen ui hint, set emulation + InputDefault *id = Input::get_singleton()->cast_to<InputDefault>(); + if (id) + id->set_emulate_touch(false); //just disable just in case + } + + singleton=this; last_checked_version=0; changing_scene=false; @@ -4120,6 +4413,7 @@ EditorNode::EditorNode() { ResourceLoader::set_abort_on_missing_resources(false); FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("file_dialog/show_hidden_files")); ResourceLoader::set_error_notify_func(this,_load_error_notify); + ResourceLoader::set_dependency_error_notify_func(this,_dependency_error_report); ResourceLoader::set_timestamp_on_load(true); ResourceSaver::set_timestamp_on_save(true); @@ -4493,6 +4787,7 @@ EditorNode::EditorNode() { p->add_separator(); p->add_item("Quick Open Scene..",FILE_QUICK_OPEN_SCENE,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_O); p->add_item("Quick Open Script..",FILE_QUICK_OPEN_SCRIPT,KEY_MASK_ALT+KEY_MASK_CMD+KEY_O); + p->add_item("Quick Search File..",FILE_QUICK_OPEN_FILE,KEY_MASK_ALT+KEY_MASK_CMD+KEY_P); p->add_separator(); PopupMenu *pm_export = memnew(PopupMenu ); @@ -4735,13 +5030,14 @@ EditorNode::EditorNode() { scene_tree_dock->set_name("Scene"); //top_pallete->add_child(scene_tree_dock); dock_slot[DOCK_SLOT_LEFT_UR]->add_child(scene_tree_dock); - +#if 0 resources_dock = memnew( ResourcesDock(this) ); resources_dock->set_name("Resources"); //top_pallete->add_child(resources_dock); dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(resources_dock); //top_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL); - +#endif + dock_slot[DOCK_SLOT_RIGHT_BL]->hide(); /*Control *editor_spacer = memnew( Control ); editor_spacer->set_custom_minimum_size(Size2(260,200)); editor_spacer->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -4766,27 +5062,40 @@ EditorNode::EditorNode() { dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(prop_editor_base); HBoxContainer *prop_editor_hb = memnew( HBoxContainer ); - prop_editor_base->add_child(prop_editor_hb); - editor_path = memnew( EditorPath(&editor_history) ); - editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); - prop_editor_hb->add_child(editor_path); - - property_editor = memnew( PropertyEditor ); - property_editor->set_autoclear(true); - property_editor->set_show_categories(true); - property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); - - property_editor->hide_top_label(); - prop_editor_base->add_child( property_editor ); - property_editor->set_undo_redo(&editor_data.get_undo_redo()); + prop_editor_base->add_child(prop_editor_hb); + resource_new_button = memnew( ToolButton ); + resource_new_button->set_tooltip("Create a new resource in memory and edit it"); + resource_new_button->set_icon(gui_base->get_icon("New","EditorIcons")); + prop_editor_hb->add_child(resource_new_button); + resource_new_button->connect("pressed",this,"_menu_option",varray(RESOURCE_NEW)); + resource_new_button->set_focus_mode(Control::FOCUS_NONE); + + resource_load_button = memnew( ToolButton ); + resource_load_button->set_tooltip("Load an existing resource from disk and edit it"); + resource_load_button->set_icon(gui_base->get_icon("Load","EditorIcons")); + prop_editor_hb->add_child(resource_load_button); + resource_load_button->connect("pressed",this,"_menu_option",varray(RESOURCE_LOAD)); + resource_load_button->set_focus_mode(Control::FOCUS_NONE); + + resource_save_button = memnew( MenuButton ); + resource_save_button->set_tooltip("Save the currently edited resource"); + resource_save_button->set_icon(gui_base->get_icon("Save","EditorIcons")); + prop_editor_hb->add_child(resource_save_button); + resource_save_button->get_popup()->add_item("Save",RESOURCE_SAVE); + resource_save_button->get_popup()->add_item("Save As..",RESOURCE_SAVE_AS); + resource_save_button->get_popup()->connect("item_pressed",this,"_menu_option"); + resource_save_button->set_focus_mode(Control::FOCUS_NONE); + resource_save_button->set_disabled(true); + + prop_editor_hb->add_spacer(); - property_back = memnew( ToolButton ); property_back->set_icon( gui_base->get_icon("Back","EditorIcons") ); property_back->set_flat(true); property_back->set_tooltip("Go to the previous edited object in history."); + property_back->set_disabled(true); prop_editor_hb->add_child( property_back ); @@ -4794,14 +5103,48 @@ EditorNode::EditorNode() { property_forward->set_icon( gui_base->get_icon("Forward","EditorIcons") ); property_forward->set_flat(true); property_forward->set_tooltip("Go to the next edited object in history."); + property_forward->set_disabled(true); prop_editor_hb->add_child( property_forward ); + + editor_history_menu = memnew( MenuButton ); + editor_history_menu->set_icon( gui_base->get_icon("History","EditorIcons")); + prop_editor_hb->add_child(editor_history_menu); + editor_history_menu->connect("about_to_show",this,"_prepare_history"); + editor_history_menu->get_popup()->connect("item_pressed",this,"_select_history"); + + + prop_editor_hb = memnew( HBoxContainer ); //again... + + prop_editor_base->add_child(prop_editor_hb); + editor_path = memnew( EditorPath(&editor_history) ); + editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + prop_editor_hb->add_child(editor_path); + + object_menu = memnew( MenuButton ); object_menu->set_icon(gui_base->get_icon("Tools","EditorIcons")); prop_editor_hb->add_child( object_menu ); object_menu->set_tooltip("Object properties."); + create_dialog = memnew( CreateDialog ); + gui_base->add_child(create_dialog); + create_dialog->set_base_type("Resource"); + create_dialog->connect("create",this,"_resource_created"); + + + property_editor = memnew( PropertyEditor ); + property_editor->set_autoclear(true); + property_editor->set_show_categories(true); + property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); + property_editor->set_use_doc_hints(true); + + property_editor->hide_top_label(); + + prop_editor_base->add_child( property_editor ); + property_editor->set_undo_redo(&editor_data.get_undo_redo()); + scenes_dock = memnew( ScenesDock(this) ); scenes_dock->set_name("FileSystem"); @@ -4929,7 +5272,11 @@ EditorNode::EditorNode() { + dependency_error = memnew( DependencyErrorDialog ); + gui_base->add_child(dependency_error); + dependency_fixer = memnew( DependencyEditor ); + gui_base->add_child( dependency_fixer ); settings_config_dialog = memnew( EditorSettingsDialog ); gui_base->add_child(settings_config_dialog); diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index d40658a056..dba2b7b86c 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -123,6 +123,7 @@ class EditorNode : public Node { FILE_OPEN_OLD_SCENE, FILE_QUICK_OPEN_SCENE, FILE_QUICK_OPEN_SCRIPT, + FILE_QUICK_OPEN_FILE, FILE_RUN_SCRIPT, FILE_OPEN_PREV, FILE_CLOSE, @@ -137,6 +138,7 @@ class EditorNode : public Node { RESOURCE_SAVE_AS, RESOURCE_UNREF, RESOURCE_COPY, + RESOURCE_PASTE, OBJECT_COPY_PARAMS, OBJECT_PASTE_PARAMS, OBJECT_UNIQUE_RESOURCES, @@ -256,11 +258,13 @@ class EditorNode : public Node { Button *property_back; Button *property_forward; SceneTreeDock *scene_tree_dock; - ResourcesDock *resources_dock; + //ResourcesDock *resources_dock; PropertyEditor *property_editor; ScenesDock *scenes_dock; EditorRunNative *run_native; + CreateDialog *create_dialog; + CallDialog *call_dialog; ConfirmationDialog *confirmation; ConfirmationDialog *import_confirmation; @@ -298,6 +302,10 @@ class EditorNode : public Node { HBoxContainer *animation_panel_hb; VBoxContainer *animation_vb; EditorPath *editor_path; + ToolButton *resource_new_button; + ToolButton *resource_load_button; + MenuButton *resource_save_button; + MenuButton *editor_history_menu; AnimationKeyEditor *animation_editor; EditorLog *log; CenterContainer *tabs_center; @@ -312,6 +320,9 @@ class EditorNode : public Node { ProgressDialog *progress_dialog; BackgroundProgress *progress_hb; + DependencyErrorDialog *dependency_error; + DependencyEditor *dependency_fixer; + TabContainer *dock_slot[DOCK_SLOT_MAX]; Rect2 dock_select_rect[DOCK_SLOT_MAX]; int dock_select_rect_over; @@ -367,6 +378,7 @@ class EditorNode : public Node { int current_option; //void _animation_visibility_toggle(); + void _resource_created(); void _resource_selected(const RES& p_res,const String& p_property=""); void _menu_option(int p_option); void _menu_confirm_current(); @@ -375,6 +387,9 @@ class EditorNode : public Node { void _property_editor_forward(); void _property_editor_back(); + void _select_history(int p_idx); + void _prepare_history(); + void _fs_changed(); void _sources_changed(bool p_exist); @@ -451,6 +466,16 @@ class EditorNode : public Node { void _save_scene_with_preview(String p_file); + Map<String,Set<String> > dependency_errors; + + static void _dependency_error_report(void *ud,const String& p_path,const String& p_dep,const String& p_type) { + EditorNode*en=(EditorNode*)ud; + if (!en->dependency_errors.has(p_path)) + en->dependency_errors[p_path]=Set<String>(); + en->dependency_errors[p_path].insert(p_dep+"::"+p_type); + + } + struct ExportDefer { String platform; String path; @@ -503,6 +528,8 @@ public: void edit_node(Node *p_node); void edit_resource(const Ref<Resource>& p_resource); void open_resource(const String& p_type=""); + + 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); @@ -534,10 +561,13 @@ public: Viewport *get_scene_root() { return scene_root; } //root of the scene being edited Error save_optimized_copy(const String& p_scene,const String& p_preset); + void fix_dependencies(const String& p_for_file); void clear_scene() { _cleanup_scene(); } - Error load_scene(const String& p_scene); + Error load_scene(const String& p_scene,bool p_ignore_broken_deps=false); Error load_resource(const String& p_scene); + bool is_scene_open(const String& p_path); + void set_current_version(uint64_t p_version); void set_current_scene(int p_idx); diff --git a/tools/editor/editor_path.cpp b/tools/editor/editor_path.cpp index 86fd79d014..94e2efe346 100644 --- a/tools/editor/editor_path.cpp +++ b/tools/editor/editor_path.cpp @@ -73,7 +73,11 @@ void EditorPath::_notification(int p_what) { if (obj->cast_to<Resource>()) { Resource *r = obj->cast_to<Resource>(); - name=r->get_name(); + if (r->get_path().is_resource_file()) + name=r->get_path().get_file(); + else + name=r->get_name(); + if (name=="") name=r->get_type(); } else if (obj->cast_to<Node>()) { diff --git a/tools/editor/editor_run.cpp b/tools/editor/editor_run.cpp index 77c5f419b1..4d07463b21 100644 --- a/tools/editor/editor_run.cpp +++ b/tools/editor/editor_run.cpp @@ -28,7 +28,7 @@ /*************************************************************************/ #include "editor_run.h" #include "globals.h" - +#include "editor_settings.h" EditorRun::Status EditorRun::get_status() const { @@ -61,6 +61,70 @@ Error EditorRun::run(const String& p_scene,const String p_custom_args,const List } } + + int screen = EditorSettings::get_singleton()->get("game_window_placement/screen"); + + if (screen==0) { + screen=OS::get_singleton()->get_current_screen(); + } else { + screen--; + } + + Rect2 screen_rect; + screen_rect.pos=OS::get_singleton()->get_screen_position(screen); + screen_rect.size=OS::get_singleton()->get_screen_size(screen); + + + Size2 desired_size; + + desired_size.x=Globals::get_singleton()->get("display/width"); + desired_size.y=Globals::get_singleton()->get("display/height"); + + Size2 test_size; + test_size.x=Globals::get_singleton()->get("display/test_width"); + test_size.y=Globals::get_singleton()->get("display/test_height"); + if (test_size.x>0 && test_size.y>0) { + + desired_size=test_size; + } + + + int window_placement=EditorSettings::get_singleton()->get("game_window_placement/rect"); + + switch(window_placement) { + case 0: { // default + + args.push_back("-p"); + args.push_back(itos(screen_rect.pos.x)+"x"+itos(screen_rect.pos.y)); + } break; + case 1: { // centered + Vector2 pos=screen_rect.pos+((screen_rect.size-desired_size)/2).floor(); + args.push_back("-p"); + args.push_back(itos(pos.x)+"x"+itos(pos.y)); + } break; + case 2: { // custom pos + Vector2 pos = EditorSettings::get_singleton()->get("game_window_placement/rect_custom_position"); + pos+=screen_rect.pos; + args.push_back("-p"); + args.push_back(itos(pos.x)+"x"+itos(pos.y)); + } break; + case 3: { // force maximized + Vector2 pos=screen_rect.pos; + args.push_back("-p"); + args.push_back(itos(pos.x)+"x"+itos(pos.y)); + args.push_back("-mx"); + + } break; + case 4: { // force fullscreen + + Vector2 pos=screen_rect.pos; + args.push_back("-p"); + args.push_back(itos(pos.x)+"x"+itos(pos.y)); + args.push_back("-f"); + } break; + } + + if (p_breakpoints.size()) { args.push_back("-bp"); diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index 2f61d4f09d..a771893bdd 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -496,6 +496,15 @@ void EditorSettings::_load_defaults() { 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("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"); + String screen_hints="Default (Same as Editor)"; + for(int i=0;i<OS::get_singleton()->get_screen_count();i++) { + screen_hints+=",Monitor "+itos(i+1); + } + set("game_window_placement/rect_custom_position",Vector2()); + set("game_window_placement/screen",0); + hints["game_window_placement/screen"]=PropertyInfo(Variant::INT,"game_window_placement/screen",PROPERTY_HINT_ENUM,screen_hints); set("on_save/compress_binary_resources",true); set("on_save/save_modified_external_resources",true); diff --git a/tools/editor/icons/icon_anchor.png b/tools/editor/icons/icon_anchor.png Binary files differnew file mode 100644 index 0000000000..1f9f9fa139 --- /dev/null +++ b/tools/editor/icons/icon_anchor.png diff --git a/tools/editor/icons/icon_control_align_bottom_center.png b/tools/editor/icons/icon_control_align_bottom_center.png Binary files differnew file mode 100644 index 0000000000..5ce9fe5c1c --- /dev/null +++ b/tools/editor/icons/icon_control_align_bottom_center.png diff --git a/tools/editor/icons/icon_control_align_bottom_left.png b/tools/editor/icons/icon_control_align_bottom_left.png Binary files differnew file mode 100644 index 0000000000..6c5129bf95 --- /dev/null +++ b/tools/editor/icons/icon_control_align_bottom_left.png diff --git a/tools/editor/icons/icon_control_align_bottom_right.png b/tools/editor/icons/icon_control_align_bottom_right.png Binary files differnew file mode 100644 index 0000000000..8857f4e940 --- /dev/null +++ b/tools/editor/icons/icon_control_align_bottom_right.png diff --git a/tools/editor/icons/icon_control_align_bottom_wide.png b/tools/editor/icons/icon_control_align_bottom_wide.png Binary files differnew file mode 100644 index 0000000000..56f009b8e4 --- /dev/null +++ b/tools/editor/icons/icon_control_align_bottom_wide.png diff --git a/tools/editor/icons/icon_control_align_center.png b/tools/editor/icons/icon_control_align_center.png Binary files differnew file mode 100644 index 0000000000..acd42525fa --- /dev/null +++ b/tools/editor/icons/icon_control_align_center.png diff --git a/tools/editor/icons/icon_control_align_center_left.png b/tools/editor/icons/icon_control_align_center_left.png Binary files differnew file mode 100644 index 0000000000..997074b097 --- /dev/null +++ b/tools/editor/icons/icon_control_align_center_left.png diff --git a/tools/editor/icons/icon_control_align_center_right.png b/tools/editor/icons/icon_control_align_center_right.png Binary files differnew file mode 100644 index 0000000000..b5cae63f7a --- /dev/null +++ b/tools/editor/icons/icon_control_align_center_right.png diff --git a/tools/editor/icons/icon_control_align_left_center.png b/tools/editor/icons/icon_control_align_left_center.png Binary files differnew file mode 100644 index 0000000000..7bb4dfb567 --- /dev/null +++ b/tools/editor/icons/icon_control_align_left_center.png diff --git a/tools/editor/icons/icon_control_align_left_wide.png b/tools/editor/icons/icon_control_align_left_wide.png Binary files differnew file mode 100644 index 0000000000..1b0a6cff95 --- /dev/null +++ b/tools/editor/icons/icon_control_align_left_wide.png diff --git a/tools/editor/icons/icon_control_align_right_center.png b/tools/editor/icons/icon_control_align_right_center.png Binary files differnew file mode 100644 index 0000000000..cf12d44c6a --- /dev/null +++ b/tools/editor/icons/icon_control_align_right_center.png diff --git a/tools/editor/icons/icon_control_align_right_wide.png b/tools/editor/icons/icon_control_align_right_wide.png Binary files differnew file mode 100644 index 0000000000..406ed25aed --- /dev/null +++ b/tools/editor/icons/icon_control_align_right_wide.png diff --git a/tools/editor/icons/icon_control_align_top_center.png b/tools/editor/icons/icon_control_align_top_center.png Binary files differnew file mode 100644 index 0000000000..da7ede984a --- /dev/null +++ b/tools/editor/icons/icon_control_align_top_center.png diff --git a/tools/editor/icons/icon_control_align_top_left.png b/tools/editor/icons/icon_control_align_top_left.png Binary files differnew file mode 100644 index 0000000000..84a224fbbe --- /dev/null +++ b/tools/editor/icons/icon_control_align_top_left.png diff --git a/tools/editor/icons/icon_control_align_top_right.png b/tools/editor/icons/icon_control_align_top_right.png Binary files differnew file mode 100644 index 0000000000..3b58eead9c --- /dev/null +++ b/tools/editor/icons/icon_control_align_top_right.png diff --git a/tools/editor/icons/icon_control_align_top_wide.png b/tools/editor/icons/icon_control_align_top_wide.png Binary files differnew file mode 100644 index 0000000000..869ae26134 --- /dev/null +++ b/tools/editor/icons/icon_control_align_top_wide.png diff --git a/tools/editor/icons/icon_control_align_wide.png b/tools/editor/icons/icon_control_align_wide.png Binary files differnew file mode 100644 index 0000000000..57a2933b25 --- /dev/null +++ b/tools/editor/icons/icon_control_align_wide.png diff --git a/tools/editor/icons/icon_control_hcenter_wide.png b/tools/editor/icons/icon_control_hcenter_wide.png Binary files differnew file mode 100644 index 0000000000..739ea5baeb --- /dev/null +++ b/tools/editor/icons/icon_control_hcenter_wide.png diff --git a/tools/editor/icons/icon_control_vcenter_wide.png b/tools/editor/icons/icon_control_vcenter_wide.png Binary files differnew file mode 100644 index 0000000000..44cbb8f344 --- /dev/null +++ b/tools/editor/icons/icon_control_vcenter_wide.png diff --git a/tools/editor/icons/icon_file_list.png b/tools/editor/icons/icon_file_list.png Binary files differindex e5e9213e61..ab790a85a5 100644 --- a/tools/editor/icons/icon_file_list.png +++ b/tools/editor/icons/icon_file_list.png diff --git a/tools/editor/icons/icon_filesystem.png b/tools/editor/icons/icon_filesystem.png Binary files differnew file mode 100644 index 0000000000..6841f9a792 --- /dev/null +++ b/tools/editor/icons/icon_filesystem.png diff --git a/tools/editor/icons/icon_history.png b/tools/editor/icons/icon_history.png Binary files differnew file mode 100644 index 0000000000..5c306c3ac9 --- /dev/null +++ b/tools/editor/icons/icon_history.png diff --git a/tools/editor/icons/icon_multi_node_edit.png b/tools/editor/icons/icon_multi_node_edit.png Binary files differnew file mode 100644 index 0000000000..357c062cbd --- /dev/null +++ b/tools/editor/icons/icon_multi_node_edit.png diff --git a/tools/editor/icons/icon_non_favorite.png b/tools/editor/icons/icon_non_favorite.png Binary files differnew file mode 100644 index 0000000000..edd806fbe8 --- /dev/null +++ b/tools/editor/icons/icon_non_favorite.png diff --git a/tools/editor/icons/icon_patch_9_frame.png b/tools/editor/icons/icon_patch_9_frame.png Binary files differnew file mode 100644 index 0000000000..c8f38fa61a --- /dev/null +++ b/tools/editor/icons/icon_patch_9_frame.png diff --git a/tools/editor/inspector_dock.cpp b/tools/editor/inspector_dock.cpp new file mode 100644 index 0000000000..57d19c3ec8 --- /dev/null +++ b/tools/editor/inspector_dock.cpp @@ -0,0 +1,22 @@ +#include "inspector_dock.h" + +#if 0 +void InspectorDock::_go_next() { + + +} + +void InspectorDock::_go_prev() { + + +} + +void InspectorDock::_bind_methods() { + +} + +InspectorDock::InspectorDock() { + + +} +#endif diff --git a/tools/editor/inspector_dock.h b/tools/editor/inspector_dock.h new file mode 100644 index 0000000000..90f043aba8 --- /dev/null +++ b/tools/editor/inspector_dock.h @@ -0,0 +1,35 @@ +#ifndef INSPECTOR_DOCK_H +#define INSPECTOR_DOCK_H + +#include "scene/gui/box_container.h" +#include "property_editor.h" + + +//this is for now bundled in EditorNode, will be moved away here eventually + +#if 0 +class InspectorDock : public VBoxContainer +{ + OBJ_TYPE(InspectorDock,VBoxContainer); + + PropertyEditor *property_editor; + + EditorHistory editor_history; + + void _go_next(); + void _go_prev(); + +protected: + + static void _bind_methods(); +public: + + EditorHistory &get_editor_history(); + + PropertyEditor *get_property_editor(); + + InspectorDock(); +}; + +#endif +#endif // INSPECTOR_DOCK_H diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp index d510333a32..d57cff850e 100644 --- a/tools/editor/io_plugins/editor_import_collada.cpp +++ b/tools/editor/io_plugins/editor_import_collada.cpp @@ -710,10 +710,126 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con //find largest source.. + /************************/ + /* ADD WEIGHTS IF EXIST */ + /************************/ + + Map<int,Vector<Collada::Vertex::Weight> > pre_weights; + + bool has_weights=false; + + if (skin_controller) { + + const Collada::SkinControllerData::Source *weight_src=NULL; + int weight_ofs=0; + + if (skin_controller->weights.sources.has("WEIGHT")) { + + String weight_id = skin_controller->weights.sources["WEIGHT"].source; + weight_ofs = skin_controller->weights.sources["WEIGHT"].offset; + if (skin_controller->sources.has(weight_id)) { + + weight_src = &skin_controller->sources[weight_id]; + + } + } + + int joint_ofs=0; + + if (skin_controller->weights.sources.has("JOINT")) { + + joint_ofs = skin_controller->weights.sources["JOINT"].offset; + } + + //should be OK, given this was pre-checked. + + int index_ofs=0; + int wstride = skin_controller->weights.sources.size(); + for(int w_i=0;w_i<skin_controller->weights.sets.size();w_i++) { + + int amount = skin_controller->weights.sets[w_i]; + + Vector<Collada::Vertex::Weight> weights; + + for (int a_i=0;a_i<amount;a_i++) { + + Collada::Vertex::Weight w; + + int read_from = index_ofs+a_i*wstride; + ERR_FAIL_INDEX_V(read_from+wstride-1,skin_controller->weights.indices.size(),ERR_INVALID_DATA); + int weight_index = skin_controller->weights.indices[read_from+weight_ofs]; + ERR_FAIL_INDEX_V(weight_index,weight_src->array.size(),ERR_INVALID_DATA); + + w.weight = weight_src->array[weight_index]; + + int bone_index = skin_controller->weights.indices[read_from+joint_ofs]; + if (bone_index==-1) + continue; //ignore this weight (refers to bind shape) + ERR_FAIL_INDEX_V(bone_index,bone_remap.size(),ERR_INVALID_DATA); + + w.bone_idx=bone_remap[bone_index]; + + + weights.push_back(w); + } + + /* FIX WEIGHTS */ + + + + weights.sort(); + + if (weights.size()>4) { + //cap to 4 and make weights add up 1 + weights.resize(4); + + } + + //make sure weights allways add up to 1 + float total=0; + for(int i=0;i<weights.size();i++) + total+=weights[i].weight; + if (total) + for(int i=0;i<weights.size();i++) + weights[i].weight/=total; + + if (weights.size()==0 || total==0) { //if nothing, add a weight to bone 0 + //no weights assigned + Collada::Vertex::Weight w; + w.bone_idx=0; + w.weight=1.0; + weights.clear(); + weights.push_back(w); + + } + + pre_weights[w_i]=weights; + + /* + for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) { + + int dst = E->get(); + ERR_EXPLAIN("invalid vertex index in array"); + ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA); + vertex_array[dst].weights=weights; + + }*/ + + + + + index_ofs+=wstride*amount; + + } + + //vertices need to be localized + has_weights=true; + + } Set<Collada::Vertex> vertex_set; //vertex set will be the vertices List<int> indices_list; //indices will be the indices - Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph) + //Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph) /**************************/ /* CREATE PRIMITIVE ARRAY */ @@ -753,11 +869,16 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con if (!p_optimize) vertex.uid=vertidx++; + + int vertex_index=p.indices[src+vertex_ofs]; //used for index field (later used by controllers) int vertex_pos = (vertex_src->stride?vertex_src->stride:3) * vertex_index; ERR_FAIL_INDEX_V(vertex_pos,vertex_src->array.size(),ERR_INVALID_DATA); vertex.vertex=Vector3(vertex_src->array[vertex_pos+0],vertex_src->array[vertex_pos+1],vertex_src->array[vertex_pos+2]); + if (pre_weights.has(vertex_index)) { + vertex.weights=pre_weights[vertex_index]; + } if (normal_src) { @@ -836,9 +957,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con vertex_set.insert(vertex); } - if (!vertex_map.has(vertex_index)) + /* if (!vertex_map.has(vertex_index)) vertex_map[vertex_index]=Set<int>(); - vertex_map[vertex_index].insert(index); //should be outside.. + vertex_map[vertex_index].insert(index); //should be outside..*/ //build triangles if needed if (j==0) prev2[0]=index; @@ -874,120 +995,10 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con vertex_array[F->get().idx]=F->get(); } - /************************/ - /* ADD WEIGHTS IF EXIST */ - /************************/ - - - bool has_weights=false; - - if (skin_controller) { - - const Collada::SkinControllerData::Source *weight_src=NULL; - int weight_ofs=0; - - if (skin_controller->weights.sources.has("WEIGHT")) { - - String weight_id = skin_controller->weights.sources["WEIGHT"].source; - weight_ofs = skin_controller->weights.sources["WEIGHT"].offset; - if (skin_controller->sources.has(weight_id)) { - - weight_src = &skin_controller->sources[weight_id]; - - } - } - - int joint_ofs=0; - - if (skin_controller->weights.sources.has("JOINT")) { - - joint_ofs = skin_controller->weights.sources["JOINT"].offset; - } - - //should be OK, given this was pre-checked. - - int index_ofs=0; - int wstride = skin_controller->weights.sources.size(); - for(int w_i=0;w_i<skin_controller->weights.sets.size();w_i++) { - - int amount = skin_controller->weights.sets[w_i]; - - if (vertex_map.has(w_i)) { //vertex may no longer be here, don't bother converting - Vector<Collada::Vertex::Weight> weights; - - for (int a_i=0;a_i<amount;a_i++) { - - Collada::Vertex::Weight w; - - int read_from = index_ofs+a_i*wstride; - ERR_FAIL_INDEX_V(read_from+wstride-1,skin_controller->weights.indices.size(),ERR_INVALID_DATA); - int weight_index = skin_controller->weights.indices[read_from+weight_ofs]; - ERR_FAIL_INDEX_V(weight_index,weight_src->array.size(),ERR_INVALID_DATA); - - w.weight = weight_src->array[weight_index]; - - int bone_index = skin_controller->weights.indices[read_from+joint_ofs]; - if (bone_index==-1) - continue; //ignore this weight (refers to bind shape) - ERR_FAIL_INDEX_V(bone_index,bone_remap.size(),ERR_INVALID_DATA); - - w.bone_idx=bone_remap[bone_index]; - - - weights.push_back(w); - } - - /* FIX WEIGHTS */ - - - - weights.sort(); - - if (weights.size()>4) { - //cap to 4 and make weights add up 1 - weights.resize(4); - - } - - //make sure weights allways add up to 1 - float total=0; - for(int i=0;i<weights.size();i++) - total+=weights[i].weight; - if (total) - for(int i=0;i<weights.size();i++) - weights[i].weight/=total; - - if (weights.size()==0 || total==0) { //if nothing, add a weight to bone 0 - //no weights assigned - Collada::Vertex::Weight w; - w.bone_idx=0; - w.weight=1.0; - weights.clear(); - weights.push_back(w); - - } - - - for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) { - - int dst = E->get(); - ERR_EXPLAIN("invalid vertex index in array"); - ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA); - vertex_array[dst].weights=weights; - - } - - } else { - //zzprint_line("no vertex found for index "+itos(w_i)); - } - - index_ofs+=wstride*amount; - - } - - //vertices need to be localized + if (has_weights) { + //if skeleton, localize Transform local_xform = p_local_xform; for(int i=0;i<vertex_array.size();i++) { @@ -1000,11 +1011,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con //vertex_array[i].tangent.normal*=-1.0; } } - - has_weights=true; - } + DVector<int> index_array; index_array.resize(indices_list.size()); DVector<int>::Write index_arrayw = index_array.write(); diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp index 4f7ec1839a..436725f6fb 100644 --- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp +++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp @@ -1068,12 +1068,14 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc //prepare atlas! Vector< Image > sources; + Vector< Image > tsources; bool alpha=false; bool crop = from->get_option("crop"); EditorProgress ep("make_atlas","Build Atlas For: "+p_path.get_file(),from->get_source_count()+3); print_line("sources: "+itos(from->get_source_count())); + for(int i=0;i<from->get_source_count();i++) { String path = EditorImportPlugin::expand_source_path(from->get_source_path(i)); @@ -1091,17 +1093,57 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc if (src.detect_alpha()) alpha=true; - sources.push_back(src); + tsources.push_back(src); } ep.step("Converting Images",sources.size()); - for(int i=0;i<sources.size();i++) { + int base_index=0; + + + Map<uint64_t,int> source_md5; + Map<int,List<int> > source_map; + + for(int i=0;i<tsources.size();i++) { + + Image src = tsources[i]; if (alpha) { - sources[i].convert(Image::FORMAT_RGBA); + src.convert(Image::FORMAT_RGBA); + } else { + src.convert(Image::FORMAT_RGB); + } + + DVector<uint8_t> data = src.get_data(); + MD5_CTX md5; + DVector<uint8_t>::Read r=data.read(); + MD5Init(&md5); + int len=data.size(); + for(int j=0;j<len;j++) { + uint8_t b = r[j]; + b>>=2; //to aid in comparing + MD5Update(&md5,(unsigned char*)&b,1); + } + MD5Final(&md5); + uint64_t *cmp = (uint64_t*)md5.digest; //less bits, but still useful for this + + tsources[i]=Image(); //clear + + if (source_md5.has(*cmp)) { + int sidx=source_md5[*cmp]; + source_map[sidx].push_back(i); + print_line("REUSING "+from->get_source_path(i)); + } else { - sources[i].convert(Image::FORMAT_RGB); + int sidx=sources.size(); + source_md5[*cmp]=sidx; + sources.push_back(src); + List<int> sm; + sm.push_back(i); + source_map[sidx]=sm; + } + + } //texturepacker is not really good for optimizing, so.. @@ -1141,28 +1183,44 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc Image atlas; atlas.create(nearest_power_of_2(dst_size.width),nearest_power_of_2(dst_size.height),0,alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB); + + atlases.resize(from->get_source_count()); + for(int i=0;i<sources.size();i++) { int x=dst_positions[i].x; int y=dst_positions[i].y; - Ref<AtlasTexture> at = memnew( AtlasTexture ); Size2 sz = Size2(sources[i].get_width(),sources[i].get_height()); + + Rect2 region; + Rect2 margin; + if (crop && sz!=crops[i].size) { Rect2 rect = crops[i]; rect.size=sz-rect.size; - at->set_region(Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height)); - at->set_margin(rect); + region=Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height); + margin=rect; atlas.blit_rect(sources[i],crops[i],Point2(x+border,y+border)); } else { - at->set_region(Rect2(x+border,y+border,sz.x,sz.y)); + region=Rect2(x+border,y+border,sz.x,sz.y); atlas.blit_rect(sources[i],Rect2(0,0,sources[i].get_width(),sources[i].get_height()),Point2(x+border,y+border)); } - String apath = p_path.get_base_dir().plus_file(from->get_source_path(i).get_file().basename()+".atex"); - print_line("Atlas Tex: "+apath); - at->set_path(apath); - atlases.push_back(at); + ERR_CONTINUE( !source_map.has(i) ); + for (List<int>::Element *E=source_map[i].front();E;E=E->next()) { + + Ref<AtlasTexture> at = memnew( AtlasTexture ); + + + at->set_region(region); + at->set_margin(margin); + String apath = p_path.get_base_dir().plus_file(from->get_source_path(E->get()).get_file().basename()+".atex"); + at->set_path(apath); + atlases[E->get()]=at; + print_line("Atlas Tex: "+apath); + + } } if (ResourceCache::has(p_path)) { texture = Ref<ImageTexture> ( ResourceCache::get(p_path)->cast_to<ImageTexture>() ); @@ -1414,6 +1472,9 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c case EditorImportExport::IMAGE_ACTION_COMPRESS_RAM: { group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM; } break; //use default + case EditorImportExport::IMAGE_ACTION_KEEP: { + return Vector<uint8_t>(); + } break; //use default } diff --git a/tools/editor/multi_node_edit.cpp b/tools/editor/multi_node_edit.cpp new file mode 100644 index 0000000000..cfa998bee9 --- /dev/null +++ b/tools/editor/multi_node_edit.cpp @@ -0,0 +1,118 @@ +#include "multi_node_edit.h" +#include "editor_node.h" + +bool MultiNodeEdit::_set(const StringName& p_name, const Variant& p_value){ + + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) + return false; + + UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action("MultiNode Set "+String(p_name)); + for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) { + + if (!es->has_node(E->get())) + continue; + + Node*n=es->get_node(E->get()); + if (!n) + continue; + + ur->add_do_property(n,p_name,p_value); + ur->add_undo_property(n,p_name,n->get(p_name)); + + } + + ur->commit_action(); + return true; +} + +bool MultiNodeEdit::_get(const StringName& p_name,Variant &r_ret) const { + + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) + return false; + + for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) { + + if (!es->has_node(E->get())) + continue; + + const Node*n=es->get_node(E->get()); + if (!n) + continue; + + bool found; + r_ret=n->get(p_name,&found); + if (found) + return true; + + } + + return false; +} + +void MultiNodeEdit::_get_property_list( List<PropertyInfo> *p_list) const{ + + HashMap<String,PLData> usage; + + Node *es = EditorNode::get_singleton()->get_edited_scene(); + if (!es) + return; + + int nc=0; + + List<PLData*> datas; + + for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) { + + if (!es->has_node(E->get())) + continue; + + Node*n=es->get_node(E->get()); + if (!n) + continue; + + List<PropertyInfo> plist; + n->get_property_list(&plist,true); + + for(List<PropertyInfo>::Element *F=plist.front();F;F=F->next()) { + + if (!usage.has(F->get().name)) { + PLData pld; + pld.uses=0; + pld.info=F->get(); + usage[F->get().name]=pld; + datas.push_back(usage.getptr(F->get().name)); + } + + usage[F->get().name].uses++; + } + + nc++; + } + + for (List<PLData*>::Element *E=datas.front();E;E=E->next()) { + + if (nc==E->get()->uses) { + p_list->push_back(E->get()->info); + } + } + + +} + +void MultiNodeEdit::clear_nodes() { + + nodes.clear(); +} + +void MultiNodeEdit::add_node(const NodePath& p_node){ + + nodes.push_back(p_node); +} + +MultiNodeEdit::MultiNodeEdit() +{ +} diff --git a/tools/editor/multi_node_edit.h b/tools/editor/multi_node_edit.h new file mode 100644 index 0000000000..5a0cabf4be --- /dev/null +++ b/tools/editor/multi_node_edit.h @@ -0,0 +1,32 @@ +#ifndef MULTI_NODE_EDIT_H +#define MULTI_NODE_EDIT_H + +#include "scene/main/node.h" + +class MultiNodeEdit : public Reference { + + OBJ_TYPE(MultiNodeEdit,Reference); + + List<NodePath> nodes; + struct PLData { + int uses; + PropertyInfo info; + }; + +protected: + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + +public: + + + + void clear_nodes(); + void add_node(const NodePath& p_node); + + MultiNodeEdit(); +}; + +#endif // MULTI_NODE_EDIT_H diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp index 05b12543d2..344e42c13b 100644 --- a/tools/editor/plugins/animation_player_editor_plugin.cpp +++ b/tools/editor/plugins/animation_player_editor_plugin.cpp @@ -549,6 +549,49 @@ void AnimationPlayerEditor::ensure_visibility() { _animation_edit(); } +Dictionary AnimationPlayerEditor::get_state() const { + + Dictionary d; + + d["visible"]=is_visible(); + if (is_visible() && player) { + d["player"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(player); + d["animation"]=player->get_current_animation(); + d["editing"]=edit_anim->is_pressed(); + } + + return d; + +} +void AnimationPlayerEditor::set_state(const Dictionary& p_state) { + + if (p_state.has("visible") && p_state["visible"]) { + + Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]); + if (n && n->cast_to<AnimationPlayer>()) { + player=n->cast_to<AnimationPlayer>(); + _update_player(); + show(); + set_process(true); + ensure_visibility(); + EditorNode::get_singleton()->animation_panel_make_visible(true); + + if (p_state.has("animation")) { + String anim = p_state["animation"]; + _select_anim_by_name(anim); + if (p_state.has("editing") && p_state["editing"]) { + + edit_anim->set_pressed(true); + _animation_edit(); + } + } + + } + } + +} + + void AnimationPlayerEditor::_animation_resource_edit() { if (animation->get_item_count()) { diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h index 9f0413088d..5705742565 100644 --- a/tools/editor/plugins/animation_player_editor_plugin.h +++ b/tools/editor/plugins/animation_player_editor_plugin.h @@ -151,6 +151,10 @@ protected: static void _bind_methods(); public: + Dictionary get_state() const; + void set_state(const Dictionary& p_state); + + void ensure_visibility(); void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo=p_undo_redo; } @@ -167,6 +171,9 @@ class AnimationPlayerEditorPlugin : public EditorPlugin { public: + virtual Dictionary get_state() const { return anim_editor->get_state(); } + virtual void set_state(const Dictionary& p_state) { anim_editor->set_state(p_state); } + virtual String get_name() const { return "Anim"; } bool has_main_screen() const { return false; } virtual void edit(Object *p_node); diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp index f2738f0a62..8fc2945450 100644 --- a/tools/editor/plugins/canvas_item_editor_plugin.cpp +++ b/tools/editor/plugins/canvas_item_editor_plugin.cpp @@ -1910,12 +1910,20 @@ void CanvasItemEditor::_notification(int p_what) { List<Node*> &selection = editor_selection->get_selected_node_list(); + bool all_control=true; + bool has_control=false; + for(List<Node*>::Element *E=selection.front();E;E=E->next()) { CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>(); if (!canvas_item || !canvas_item->is_visible()) continue; + if (canvas_item->cast_to<Control>()) + has_control=true; + else + all_control=false; + CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); if (!se) continue; @@ -1932,6 +1940,13 @@ void CanvasItemEditor::_notification(int p_what) { } + bool show_anchor = all_control && has_control; + if (show_anchor != !anchor_menu->is_hidden()) { + if (show_anchor) + anchor_menu->show(); + else + anchor_menu->hide(); + } for(Map<ObjectID,BoneList>::Element *E=bone_list.front();E;E=E->next()) { @@ -1974,6 +1989,32 @@ void CanvasItemEditor::_notification(int p_what) { ungroup_button->set_icon(get_icon("Ungroup","EditorIcons")); key_insert_button->set_icon(get_icon("Key","EditorIcons")); + + //anchor_menu->add_icon_override("Align Top Left"); + anchor_menu->set_icon(get_icon("Anchor","EditorIcons")); + PopupMenu *p=anchor_menu->get_popup(); + + p->add_icon_item(get_icon("ControlAlignTopLeft","EditorIcons"),"Top Left",ANCHOR_ALIGN_TOP_LEFT); + p->add_icon_item(get_icon("ControlAlignTopRight","EditorIcons"),"Top Right",ANCHOR_ALIGN_TOP_RIGHT); + p->add_icon_item(get_icon("ControlAlignBottomRight","EditorIcons"),"Bottom Right",ANCHOR_ALIGN_BOTTOM_RIGHT); + p->add_icon_item(get_icon("ControlAlignBottomLeft","EditorIcons"),"Bottom Left",ANCHOR_ALIGN_BOTTOM_LEFT); + p->add_separator(); + p->add_icon_item(get_icon("ControlAlignLeftCenter","EditorIcons"),"Center Left",ANCHOR_ALIGN_CENTER_LEFT); + p->add_icon_item(get_icon("ControlAlignTopCenter","EditorIcons"),"Center Top",ANCHOR_ALIGN_CENTER_TOP); + p->add_icon_item(get_icon("ControlAlignRightCenter","EditorIcons"),"Center Right",ANCHOR_ALIGN_CENTER_RIGHT); + p->add_icon_item(get_icon("ControlAlignBottomCenter","EditorIcons"),"Center Bottom",ANCHOR_ALIGN_CENTER_BOTTOM); + p->add_icon_item(get_icon("ControlAlignCenter","EditorIcons"),"Center",ANCHOR_ALIGN_CENTER); + p->add_separator(); + p->add_icon_item(get_icon("ControlAlignLeftWide","EditorIcons"),"Left Wide",ANCHOR_ALIGN_LEFT_WIDE); + p->add_icon_item(get_icon("ControlAlignTopWide","EditorIcons"),"Top Wide",ANCHOR_ALIGN_TOP_WIDE); + p->add_icon_item(get_icon("ControlAlignRightWide","EditorIcons"),"Right Wide",ANCHOR_ALIGN_RIGHT_WIDE); + p->add_icon_item(get_icon("ControlAlignBottomWide","EditorIcons"),"Bottom Wide",ANCHOR_ALIGN_BOTTOM_WIDE); + p->add_icon_item(get_icon("ControlVcenterWide","EditorIcons"),"VCenter Wide ",ANCHOR_ALIGN_VCENTER_WIDE); + p->add_icon_item(get_icon("ControlHcenterWide","EditorIcons"),"HCenter Wide ",ANCHOR_ALIGN_HCENTER_WIDE); + p->add_separator(); + p->add_icon_item(get_icon("ControlAlignWide","EditorIcons"),"Full Rect",ANCHOR_ALIGN_WIDE); + + } if (p_what==NOTIFICATION_READY) { @@ -2179,6 +2220,27 @@ void CanvasItemEditor::_update_scroll(float) { } +void CanvasItemEditor::_set_anchor(Control::AnchorType p_left,Control::AnchorType p_top,Control::AnchorType p_right,Control::AnchorType p_bottom) { + List<Node*> &selection = editor_selection->get_selected_node_list(); + + undo_redo->create_action("Change Anchors"); + for(List<Node*>::Element *E=selection.front();E;E=E->next()) { + + Control *c = E->get()->cast_to<Control>(); + + undo_redo->add_do_method(c,"set_anchor",MARGIN_LEFT,p_left); + undo_redo->add_do_method(c,"set_anchor",MARGIN_TOP,p_top); + undo_redo->add_do_method(c,"set_anchor",MARGIN_RIGHT,p_right); + undo_redo->add_do_method(c,"set_anchor",MARGIN_BOTTOM,p_bottom); + undo_redo->add_undo_method(c,"set_anchor",MARGIN_LEFT,c->get_anchor(MARGIN_LEFT)); + undo_redo->add_undo_method(c,"set_anchor",MARGIN_TOP,c->get_anchor(MARGIN_TOP)); + undo_redo->add_undo_method(c,"set_anchor",MARGIN_RIGHT,c->get_anchor(MARGIN_RIGHT)); + undo_redo->add_undo_method(c,"set_anchor",MARGIN_BOTTOM,c->get_anchor(MARGIN_BOTTOM)); + } + + undo_redo->commit_action(); + +} void CanvasItemEditor::_popup_callback(int p_op) { @@ -2381,6 +2443,56 @@ void CanvasItemEditor::_popup_callback(int p_op) { case SPACE_VERTICAL: { //space_selected_items< proj_vector2_y, compare_items_y >(); } break; + case ANCHOR_ALIGN_TOP_LEFT: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN); + } break; + case ANCHOR_ALIGN_TOP_RIGHT: { + _set_anchor(ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN); + } break; + case ANCHOR_ALIGN_BOTTOM_LEFT: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END); + } break; + case ANCHOR_ALIGN_BOTTOM_RIGHT: { + _set_anchor(ANCHOR_END,ANCHOR_END,ANCHOR_END,ANCHOR_END); + } break; + case ANCHOR_ALIGN_CENTER_LEFT: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER); + } break; + case ANCHOR_ALIGN_CENTER_RIGHT: { + + _set_anchor(ANCHOR_END,ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER); + } break; + case ANCHOR_ALIGN_CENTER_TOP: { + _set_anchor(ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_BEGIN); + } break; + case ANCHOR_ALIGN_CENTER_BOTTOM: { + _set_anchor(ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER,ANCHOR_END); + } break; + case ANCHOR_ALIGN_CENTER: { + _set_anchor(ANCHOR_CENTER,ANCHOR_CENTER,ANCHOR_CENTER,ANCHOR_CENTER); + } break; + case ANCHOR_ALIGN_TOP_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN); + } break; + case ANCHOR_ALIGN_LEFT_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END); + } break; + case ANCHOR_ALIGN_RIGHT_WIDE: { + _set_anchor(ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END); + } break; + case ANCHOR_ALIGN_BOTTOM_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END,ANCHOR_END); + } break; + case ANCHOR_ALIGN_VCENTER_WIDE: { + _set_anchor(ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_END); + } break; + case ANCHOR_ALIGN_HCENTER_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER); + } break; + case ANCHOR_ALIGN_WIDE: { + _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END); + } break; + case ANIM_INSERT_KEY: case ANIM_INSERT_KEY_EXISTING: { @@ -2999,6 +3111,14 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->add_item("Center Selection", VIEW_CENTER_TO_SELECTION, KEY_F); p->add_item("Frame Selection", VIEW_FRAME_TO_SELECTION, KEY_MASK_CMD|KEY_F); + anchor_menu = memnew( MenuButton ); + anchor_menu->set_text("Anchor"); + hb->add_child(anchor_menu); + anchor_menu->get_popup()->connect("item_pressed", this,"_popup_callback"); + anchor_menu->hide(); + + //p = anchor_menu->get_popup(); + animation_hb = memnew( HBoxContainer ); diff --git a/tools/editor/plugins/canvas_item_editor_plugin.h b/tools/editor/plugins/canvas_item_editor_plugin.h index 48a34e2d07..485422028e 100644 --- a/tools/editor/plugins/canvas_item_editor_plugin.h +++ b/tools/editor/plugins/canvas_item_editor_plugin.h @@ -90,6 +90,23 @@ class CanvasItemEditor : public VBoxContainer { UNGROUP_SELECTED, ALIGN_HORIZONTAL, ALIGN_VERTICAL, + ANCHOR_ALIGN_TOP_LEFT, + ANCHOR_ALIGN_TOP_RIGHT, + ANCHOR_ALIGN_BOTTOM_LEFT, + ANCHOR_ALIGN_BOTTOM_RIGHT, + ANCHOR_ALIGN_CENTER_LEFT, + ANCHOR_ALIGN_CENTER_RIGHT, + ANCHOR_ALIGN_CENTER_TOP, + ANCHOR_ALIGN_CENTER_BOTTOM, + ANCHOR_ALIGN_CENTER, + ANCHOR_ALIGN_TOP_WIDE, + ANCHOR_ALIGN_LEFT_WIDE, + ANCHOR_ALIGN_RIGHT_WIDE, + ANCHOR_ALIGN_BOTTOM_WIDE, + ANCHOR_ALIGN_VCENTER_WIDE, + ANCHOR_ALIGN_HCENTER_WIDE, + ANCHOR_ALIGN_WIDE, + SPACE_HORIZONTAL, SPACE_VERTICAL, EXPAND_TO_PARENT, @@ -225,6 +242,7 @@ class CanvasItemEditor : public VBoxContainer { MenuButton *view_menu; HBoxContainer *animation_hb; MenuButton *animation_menu; + MenuButton *anchor_menu; Button *key_loc_button; Button *key_rot_button; @@ -305,6 +323,8 @@ class CanvasItemEditor : public VBoxContainer { void _viewport_input_event(const InputEvent& p_event); void _viewport_draw(); + void _set_anchor(Control::AnchorType p_left,Control::AnchorType p_top,Control::AnchorType p_right,Control::AnchorType p_bottom); + HSplitContainer *palette_split; VSplitContainer *bottom_split; diff --git a/tools/editor/plugins/mesh_editor_plugin.cpp b/tools/editor/plugins/mesh_editor_plugin.cpp index 2c64b2eb6b..13d4c8db5a 100644 --- a/tools/editor/plugins/mesh_editor_plugin.cpp +++ b/tools/editor/plugins/mesh_editor_plugin.cpp @@ -216,6 +216,8 @@ MeshInstanceEditor::MeshInstanceEditor() { SpatialEditor::get_singleton()->add_control_to_menu_panel(options); options->set_text("Mesh"); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance","EditorIcons")); + options->get_popup()->add_item("Create Trimesh Static Body",MENU_OPTION_CREATE_STATIC_TRIMESH_BODY); options->get_popup()->add_item("Create Convex Static Body",MENU_OPTION_CREATE_STATIC_CONVEX_BODY); options->get_popup()->add_separator(); diff --git a/tools/editor/plugins/multimesh_editor_plugin.cpp b/tools/editor/plugins/multimesh_editor_plugin.cpp index 0df906117e..3c88b1d3a8 100644 --- a/tools/editor/plugins/multimesh_editor_plugin.cpp +++ b/tools/editor/plugins/multimesh_editor_plugin.cpp @@ -330,6 +330,8 @@ MultiMeshEditor::MultiMeshEditor() { options->set_area_as_parent_rect(); options->set_text("MultiMesh"); + options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MultiMeshInstance","EditorIcons")); + options->get_popup()->add_item("Populate Surface"); options->get_popup()->connect("item_pressed", this,"_menu_option"); diff --git a/tools/editor/plugins/particles_2d_editor_plugin.cpp b/tools/editor/plugins/particles_2d_editor_plugin.cpp index fdf534a3a8..dadfa8bfdc 100644 --- a/tools/editor/plugins/particles_2d_editor_plugin.cpp +++ b/tools/editor/plugins/particles_2d_editor_plugin.cpp @@ -146,6 +146,7 @@ void Particles2DEditorPlugin::_notification(int p_what) { if (p_what==NOTIFICATION_ENTER_TREE) { menu->get_popup()->connect("item_pressed",this,"_menu_callback"); + menu->set_icon(menu->get_popup()->get_icon("Particles2D","EditorIcons")); file->connect("file_selected",this,"_file_selected"); } } diff --git a/tools/editor/plugins/particles_editor_plugin.cpp b/tools/editor/plugins/particles_editor_plugin.cpp index f6f01d82ca..5c84d9a86a 100644 --- a/tools/editor/plugins/particles_editor_plugin.cpp +++ b/tools/editor/plugins/particles_editor_plugin.cpp @@ -111,6 +111,7 @@ void ParticlesEditor::_populate() { void ParticlesEditor::_notification(int p_notification) { if (p_notification==NOTIFICATION_ENTER_TREE) { + options->set_icon(options->get_popup()->get_icon("Particles","EditorIcons")); } } diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp index 77663f39c0..8fc6a6931e 100644 --- a/tools/editor/plugins/spatial_editor_plugin.cpp +++ b/tools/editor/plugins/spatial_editor_plugin.cpp @@ -2168,7 +2168,18 @@ void SpatialEditorViewport::set_state(const Dictionary& p_state) { view_menu->get_popup()->set_item_checked( idx, listener ); } - + if (p_state.has("previewing")) { + Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]); + if (pv && pv->cast_to<Camera>()) { + previewing=pv->cast_to<Camera>(); + previewing->connect("exit_tree",this,"_preview_exited_scene"); + VS::get_singleton()->viewport_attach_camera( viewport->get_viewport(), previewing->get_camera() ); //replace + view_menu->hide(); + surface->update(); + preview_camera->set_pressed(true); + preview_camera->show(); + } + } } Dictionary SpatialEditorViewport::get_state() const { @@ -2181,6 +2192,10 @@ Dictionary SpatialEditorViewport::get_state() const { d["use_environment"]=camera->get_environment().is_valid(); d["use_orthogonal"]=camera->get_projection()==Camera::PROJECTION_ORTHOGONAL; d["listener"]=viewport->is_audio_listener(); + if (previewing) { + d["previewing"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing); + } + return d; } diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp index a087f23c25..9f871fd3ab 100644 --- a/tools/editor/project_export.cpp +++ b/tools/editor/project_export.cpp @@ -80,7 +80,7 @@ bool ProjectExportDialog::_create_tree(TreeItem *p_parent,EditorFileSystemDirect String path = p_dir->get_file_path(i); fitem->set_tooltip(0,path); fitem->set_metadata(0,path); - Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),"EditorIcons")?p_dir->get_file_type(i):String("Object")),"EditorIcons"); + Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),ei)?p_dir->get_file_type(i):ot),ei); fitem->set_icon(0,icon); fitem->set_cell_mode(1,TreeItem::CELL_MODE_RANGE); @@ -1216,6 +1216,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { group_image_action->add_item("Default"); group_image_action->add_item("Compress Disk"); group_image_action->add_item("Compress RAM"); + group_image_action->add_item("Keep Original"); group_options->add_margin_child("Compress Mode:",group_image_action); group_image_action->connect("item_selected",this,"_group_changed"); @@ -1372,6 +1373,8 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck"); updating_script=false; + ei="EditorIcons"; + ot="Object"; } diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h index c88233ae01..d85e688e58 100644 --- a/tools/editor/project_export.h +++ b/tools/editor/project_export.h @@ -78,6 +78,9 @@ private: HBoxContainer *plat_errors; Label *platform_error_string; + StringName ei; + StringName ot; + Tree * tree; EditorFileDialog *pck_export; diff --git a/tools/editor/project_settings.cpp b/tools/editor/project_settings.cpp index fea9c705ef..25a2750166 100644 --- a/tools/editor/project_settings.cpp +++ b/tools/editor/project_settings.cpp @@ -771,18 +771,47 @@ void ProjectSettings::_autoload_add() { void ProjectSettings::_autoload_delete(Object *p_item,int p_column, int p_button) { + TreeItem *ti=p_item->cast_to<TreeItem>(); String name = "autoload/"+ti->get_text(0); - undo_redo->create_action("Remove Autoload"); - undo_redo->add_do_property(Globals::get_singleton(),name,Variant()); - undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name)); - undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",name,true); - undo_redo->add_do_method(this,"_update_autoload"); - undo_redo->add_undo_method(this,"_update_autoload"); - undo_redo->add_do_method(this,"_settings_changed"); - undo_redo->add_undo_method(this,"_settings_changed"); - undo_redo->commit_action(); + if (p_button==0) { + //delete + undo_redo->create_action("Remove Autoload"); + undo_redo->add_do_property(Globals::get_singleton(),name,Variant()); + undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name)); + undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",name,true); + undo_redo->add_do_method(this,"_update_autoload"); + undo_redo->add_undo_method(this,"_update_autoload"); + undo_redo->add_do_method(this,"_settings_changed"); + undo_redo->add_undo_method(this,"_settings_changed"); + undo_redo->commit_action(); + } else { + + TreeItem *swap; + + if (p_button==1) { + swap=ti->get_prev(); + } else if (p_button==2) { + swap=ti->get_next(); + } + if (!swap) + return; + + String swap_name= "autoload/"+swap->get_text(0); + + undo_redo->create_action("Move Autoload"); + undo_redo->add_do_method(Globals::get_singleton(),"set_order",swap_name,Globals::get_singleton()->get_order(name)); + undo_redo->add_do_method(Globals::get_singleton(),"set_order",name,Globals::get_singleton()->get_order(swap_name)); + undo_redo->add_undo_method(Globals::get_singleton(),"set_order",swap_name,Globals::get_singleton()->get_order(swap_name)); + undo_redo->add_undo_method(Globals::get_singleton(),"set_order",name,Globals::get_singleton()->get_order(name)); + undo_redo->add_do_method(this,"_update_autoload"); + undo_redo->add_undo_method(this,"_update_autoload"); + undo_redo->add_do_method(this,"_settings_changed"); + undo_redo->add_undo_method(this,"_settings_changed"); + undo_redo->commit_action(); + + } } @@ -1134,6 +1163,8 @@ void ProjectSettings::_update_autoload() { TreeItem *t = autoload_list->create_item(root); t->set_text(0,name); t->set_text(1,Globals::get_singleton()->get(pi.name)); + t->add_button(1,get_icon("MoveUp","EditorIcons"),1); + t->add_button(1,get_icon("MoveDown","EditorIcons"),2); t->add_button(1,get_icon("Del","EditorIcons"),0); } diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp index 955c426d2b..b513e32c13 100644 --- a/tools/editor/property_editor.cpp +++ b/tools/editor/property_editor.cpp @@ -39,6 +39,9 @@ #include "editor_settings.h" #include "editor_import_export.h" #include "editor_node.h" +#include "multi_node_edit.h" +#include "array_property_edit.h" +#include "editor_help.h" void CustomPropertyEditor::_notification(int p_what) { @@ -2212,6 +2215,23 @@ void PropertyEditor::update_tree() { sep->set_selectable(1,false); sep->set_custom_bg_color(0,get_color("prop_category","Editor")); sep->set_custom_bg_color(1,get_color("prop_category","Editor")); + + if (use_doc_hints) { + StringName type=p.name; + if (!class_descr_cache.has(type)) { + + String descr; + DocData *dd=EditorHelp::get_doc_data(); + Map<String,DocData::ClassDoc>::Element *E=dd->class_list.find(type); + if (E) { + descr=E->get().brief_description; + } + class_descr_cache[type]=descr.world_wrap(80); + + } + + sep->set_tooltip(0,"Class: "+p.name+":\n\n"+class_descr_cache[type]); + } //sep->set_custom_color(0,Color(1,1,1)); @@ -2265,6 +2285,42 @@ void PropertyEditor::update_tree() { item->set_tooltip(0, p.name); + if (use_doc_hints) { + StringName setter; + StringName type; + if (ObjectTypeDB::get_setter_and_type_for_property(obj->get_type_name(),p.name,type,setter)) { + + String descr; + bool found=false; + Map<StringName,Map<StringName,String> >::Element *E=descr_cache.find(type); + if (E) { + + Map<StringName,String>::Element *F=E->get().find(setter); + if (F) { + found=true; + descr=F->get(); + } + } + if (!found) { + + DocData *dd=EditorHelp::get_doc_data(); + Map<String,DocData::ClassDoc>::Element *E=dd->class_list.find(type); + if (E) { + for(int i=0;i<E->get().methods.size();i++) { + if (E->get().methods[i].name==setter.operator String()) { + descr=E->get().methods[i].description.strip_edges().world_wrap(80); + } + } + } + + descr_cache[type][setter]=descr; + } + + item->set_tooltip(0, "Property: "+p.name+"\n\n"+descr); + } + } + //EditorHelp::get_doc_data(); + Dictionary d; d["name"]=p.name; d["type"]=(int)p.type; @@ -2347,8 +2403,10 @@ void PropertyEditor::update_tree() { item->set_cell_mode( 1, TreeItem::CELL_MODE_RANGE ); + if (p.hint==PROPERTY_HINT_SPRITE_FRAME) { + item->set_range_config(1,0,99999,1); - if (p.hint==PROPERTY_HINT_RANGE || p.hint==PROPERTY_HINT_EXP_RANGE) { + } else if (p.hint==PROPERTY_HINT_RANGE || p.hint==PROPERTY_HINT_EXP_RANGE) { int c = p.hint_string.get_slice_count(","); float min=0,max=100,step=1; @@ -2449,11 +2507,32 @@ void PropertyEditor::update_tree() { } } break; + case Variant::ARRAY: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Array["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Array[]"); + item->set_icon( 0, get_icon("ArrayData","EditorIcons") ); + + + } break; + case Variant::INT_ARRAY: { item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); - item->set_editable( 1, !read_only ); - item->set_text(1,"[IntArray]"); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"IntArray["+itos(v.call("size"))+"]"); + else + item->set_text(1,"IntArray[]"); item->set_icon( 0, get_icon("ArrayInt","EditorIcons") ); @@ -2461,26 +2540,86 @@ void PropertyEditor::update_tree() { case Variant::REAL_ARRAY: { item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); - item->set_editable( 1, !read_only ); - item->set_text(1,"[RealArray]"); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"FloatArray["+itos(v.call("size"))+"]"); + else + item->set_text(1,"FloatArray[]"); item->set_icon( 0, get_icon("ArrayReal","EditorIcons") ); + } break; case Variant::STRING_ARRAY: { item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); - item->set_editable( 1, !read_only ); - item->set_text(1,"[StringArray]"); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"String["+itos(v.call("size"))+"]"); + else + item->set_text(1,"String[]"); item->set_icon( 0, get_icon("ArrayString","EditorIcons") ); + } break; case Variant::RAW_ARRAY: { item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); - item->set_editable( 1, !read_only ); - item->set_text(1,"[Raw Data]"); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Byte["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Byte[]"); item->set_icon( 0, get_icon("ArrayData","EditorIcons") ); + + } break; + case Variant::VECTOR2_ARRAY: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Vector2["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Vector2[]"); + item->set_icon( 0, get_icon("Vector2","EditorIcons") ); + + + } break; + case Variant::VECTOR3_ARRAY: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Vector3["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Vector3[]"); + item->set_icon( 0, get_icon("Vector","EditorIcons") ); + + + } break; + case Variant::COLOR_ARRAY: { + + item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM ); + item->add_button(1,get_icon("EditResource","EditorIcons")); + + Variant v = obj->get(p.name); + if (v.is_array()) + item->set_text(1,"Color["+itos(v.call("size"))+"]"); + else + item->set_text(1,"Color[]"); + item->set_icon( 0, get_icon("Color","EditorIcons") ); + + } break; case Variant::VECTOR2: { @@ -2676,7 +2815,7 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) { } } - if (!undo_redo) { + if (!undo_redo || obj->cast_to<MultiNodeEdit>() || obj->cast_to<ArrayPropertyEdit>()) { //kind of hacky obj->set(p_name,p_value); _changed_callbacks(obj,p_name); @@ -2996,6 +3135,19 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { emit_signal("resource_selected",r,n); } + } else if (t==Variant::ARRAY || t==Variant::INT_ARRAY || t==Variant::REAL_ARRAY || t==Variant::STRING_ARRAY || t==Variant::VECTOR2_ARRAY || t==Variant::VECTOR3_ARRAY || t==Variant::COLOR_ARRAY || t==Variant::RAW_ARRAY) { + + Variant v = obj->get(n); + + if (v.get_type()!=t) { + Variant::CallError ce; + v=Variant::construct(Variant::Type(t),NULL,0,ce); + } + + Ref<ArrayPropertyEdit> ape = memnew( ArrayPropertyEdit ); + ape->edit(obj,n,Variant::Type(t)); + + EditorNode::get_singleton()->push_item(ape.ptr()); } } } @@ -3181,6 +3333,7 @@ PropertyEditor::PropertyEditor() { read_only=false; show_categories=false; refresh_countdown=0; + use_doc_hints=false; } diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h index de5cac8711..36ecc794ed 100644 --- a/tools/editor/property_editor.h +++ b/tools/editor/property_editor.h @@ -95,6 +95,7 @@ class CustomPropertyEditor : public Popup { Button *checks20[20]; + Control *easing_draw; Object* owner; @@ -157,9 +158,13 @@ class PropertyEditor : public Control { bool read_only; bool show_categories; float refresh_countdown; + bool use_doc_hints; HashMap<String,String> pending; String selected_property; + + Map<StringName,Map<StringName,String> > descr_cache; + Map<StringName,String > class_descr_cache; CustomPropertyEditor *custom_editor; @@ -217,6 +222,7 @@ public: void set_autoclear(bool p_enable); void set_show_categories(bool p_show); + void set_use_doc_hints(bool p_enable) { use_doc_hints=p_enable; } PropertyEditor(); ~PropertyEditor(); diff --git a/tools/editor/quick_open.cpp b/tools/editor/quick_open.cpp index 749318386c..6135a4ab64 100644 --- a/tools/editor/quick_open.cpp +++ b/tools/editor/quick_open.cpp @@ -30,8 +30,9 @@ #include "os/keyboard.h" -void EditorQuickOpen::popup(const String& p_base, bool p_dontclear) { +void EditorQuickOpen::popup(const StringName &p_base, bool p_dontclear, bool p_add_dirs) { + add_directories=p_add_dirs; popup_centered_ratio(0.6); if (p_dontclear) search_box->select_all(); @@ -66,27 +67,53 @@ void EditorQuickOpen::_sbox_input(const InputEvent& p_ie) { void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd) { - for(int i=0;i<efsd->get_subdir_count();i++) { + if (!add_directories) { + for(int i=0;i<efsd->get_subdir_count();i++) { - _parse_fs(efsd->get_subdir(i)); + _parse_fs(efsd->get_subdir(i)); + } } + TreeItem *root = search_options->get_root(); + + if (add_directories) { + String path = efsd->get_path(); + if (!path.ends_with("/")) + path+="/"; + if (path!="res://") { + path=path.substr(6,path.length()); + if (path.findn(search_box->get_text())!=-1) { + TreeItem *ti = search_options->create_item(root); + ti->set_text(0,path); + Ref<Texture> icon = get_icon("folder","FileDialog"); + ti->set_icon(0,icon); + } + } + } for(int i=0;i<efsd->get_file_count();i++) { String file = efsd->get_file_path(i); file=file.substr(6,file.length()); if (ObjectTypeDB::is_type(efsd->get_file_type(i),base_type) && (search_box->get_text()=="" || file.findn(search_box->get_text())!=-1)) { - TreeItem *root = search_options->get_root(); TreeItem *ti = search_options->create_item(root); ti->set_text(0,file); - Ref<Texture> icon = get_icon( (has_icon(efsd->get_file_type(i),"EditorIcons")?efsd->get_file_type(i):String("Object")),"EditorIcons"); + Ref<Texture> icon = get_icon( (has_icon(efsd->get_file_type(i),ei)?efsd->get_file_type(i):ot),ei); ti->set_icon(0,icon); if (root->get_children()==ti) ti->select(0); } } + + + if (add_directories) { + for(int i=0;i<efsd->get_subdir_count();i++) { + + _parse_fs(efsd->get_subdir(i)); + } + } + } void EditorQuickOpen::_update_search() { @@ -118,7 +145,7 @@ void EditorQuickOpen::_notification(int p_what) { } -String EditorQuickOpen::get_base_type() const { +StringName EditorQuickOpen::get_base_type() const { return base_type; } @@ -152,4 +179,7 @@ EditorQuickOpen::EditorQuickOpen() { set_hide_on_ok(false); search_options->connect("item_activated",this,"_confirmed"); search_options->set_hide_root(true); + ei="EditorIcons"; + ot="Object"; + add_directories=false; } diff --git a/tools/editor/quick_open.h b/tools/editor/quick_open.h index 63652a442a..8b38256d39 100644 --- a/tools/editor/quick_open.h +++ b/tools/editor/quick_open.h @@ -38,7 +38,11 @@ class EditorQuickOpen : public ConfirmationDialog { LineEdit *search_box; Tree *search_options; - String base_type; + StringName base_type; + StringName ei; + StringName ot; + bool add_directories; + void _update_search(); @@ -55,9 +59,9 @@ protected: static void _bind_methods(); public: - String get_base_type() const; + StringName get_base_type() const; - void popup(const String& p_base,bool p_dontclear=false); + void popup(const StringName& p_base,bool p_dontclear=false,bool p_add_dirs=false); EditorQuickOpen(); }; diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp index ae0b58a665..276f2dea33 100644 --- a/tools/editor/scene_tree_dock.cpp +++ b/tools/editor/scene_tree_dock.cpp @@ -35,7 +35,7 @@ #include "tools/editor/plugins/canvas_item_editor_plugin.h" #include "script_editor_debugger.h" #include "tools/editor/plugins/script_editor_plugin.h" - +#include "multi_node_edit.h" void SceneTreeDock::_unhandled_key_input(InputEvent p_event) { @@ -450,6 +450,19 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { reparent_dialog->set_current( nodeset ); } break; + case TOOL_MULTI_EDIT: { + + Node*root=EditorNode::get_singleton()->get_edited_scene(); + if (!root) + break; + Ref<MultiNodeEdit> mne = memnew( MultiNodeEdit ); + for (const Map<Node*,Object*>::Element *E=EditorNode::get_singleton()->get_editor_selection()->get_selection().front();E;E=E->next()) { + mne->add_node(root->get_path_to(E->key())); + } + + EditorNode::get_singleton()->push_item(mne.ptr()); + + } break; case TOOL_ERASE: { List<Node*> remove_list = editor_selection->get_selected_node_list(); @@ -507,6 +520,7 @@ void SceneTreeDock::_notification(int p_what) { "MoveDown", "Duplicate", "Reparent", + "MultiNodeEdit", "Remove", }; @@ -515,6 +529,8 @@ void SceneTreeDock::_notification(int p_what) { for(int i=0;i<TOOL_BUTTON_MAX;i++) tool_buttons[i]->set_icon(get_icon(button_names[i],"EditorIcons")); + EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed",this,"_selection_changed"); + } break; } } @@ -1075,9 +1091,19 @@ void SceneTreeDock::_update_tool_buttons() { tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root); tool_buttons[TOOL_REPARENT]->set_disabled(disable_root); tool_buttons[TOOL_ERASE]->set_disabled(disable); + tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2); + } + +void SceneTreeDock::_selection_changed() { + + tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2); + +} + + void SceneTreeDock::_create() { @@ -1262,6 +1288,7 @@ void SceneTreeDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_delete_confirm"),&SceneTreeDock::_delete_confirm); ObjectTypeDB::bind_method(_MD("_node_prerenamed"),&SceneTreeDock::_node_prerenamed); ObjectTypeDB::bind_method(_MD("_import_subscene"),&SceneTreeDock::_import_subscene); + ObjectTypeDB::bind_method(_MD("_selection_changed"),&SceneTreeDock::_selection_changed); ObjectTypeDB::bind_method(_MD("instance"),&SceneTreeDock::instance); } @@ -1365,6 +1392,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec hbc_bottom->add_spacer(); tb = memnew( ToolButton ); + tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_MULTI_EDIT, false)); + tb->set_tooltip("Multi-Edit Selected Nodes"); + hbc_bottom->add_child(tb); + tool_buttons[TOOL_MULTI_EDIT]=tb; + + tb = memnew( ToolButton ); tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_ERASE, false)); tb->set_tooltip("Erase Selected Node(s)"); hbc_bottom->add_child(tb); diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h index f0bbbad6be..b1c53d2ff9 100644 --- a/tools/editor/scene_tree_dock.h +++ b/tools/editor/scene_tree_dock.h @@ -62,6 +62,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_MOVE_DOWN, TOOL_DUPLICATE, TOOL_REPARENT, + TOOL_MULTI_EDIT, TOOL_ERASE, TOOL_BUTTON_MAX }; @@ -119,6 +120,7 @@ class SceneTreeDock : public VBoxContainer { void _import_subscene(); bool _validate_no_foreign(); + void _selection_changed(); void _fill_path_renames(Vector<StringName> base_path,Vector<StringName> new_base_path,Node * p_node, List<Pair<NodePath,NodePath> > *p_renames); diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp index 9153616775..7d9c5b24b2 100644 --- a/tools/editor/scenes_dock.cpp +++ b/tools/editor/scenes_dock.cpp @@ -35,15 +35,30 @@ #include "os/os.h" #include "editor_node.h" +#include "editor_settings.h" + bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir) { - String search_term = tree_filter->get_search_term(); - ScenesDockFilter::FilterOption file_filter = tree_filter->get_file_filter(); TreeItem *item = tree->create_item(p_parent); - item->set_text(0,p_dir->get_name()+"/"); + String dname=p_dir->get_name(); + if (dname=="") + dname="res://"; + + item->set_text(0,dname); item->set_icon(0,get_icon("Folder","EditorIcons")); - item->set_custom_bg_color(0,get_color("prop_subsection","Editor")); + item->set_selectable(0,true); + String lpath = p_dir->get_path(); + if (lpath!="res://" && lpath.ends_with("/")) { + lpath=lpath.substr(0,lpath.length()-1); + } + item->set_metadata(0,lpath); + if (lpath==path) { + item->select(0); + } + + + //item->set_custom_bg_color(0,get_color("prop_subsection","Editor")); bool has_items=false; @@ -52,7 +67,7 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di if (_create_tree(item,p_dir->get_subdir(i))) has_items=true; } - +#if 0 for (int i=0;i<p_dir->get_file_count();i++) { String file_name = p_dir->get_file(i); @@ -89,13 +104,13 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di has_items=true; } - - if (!has_items) { +#endif + /*if (!has_items) { memdelete(item); return false; - } + }*/ return true; } @@ -105,7 +120,28 @@ void ScenesDock::_update_tree() { tree->clear(); updating_tree=true; - _create_tree(NULL,EditorFileSystem::get_singleton()->get_filesystem()); + TreeItem *root = tree->create_item(); + TreeItem *favorites = tree->create_item(root); + favorites->set_icon(0, get_icon("Favorites","EditorIcons") ); + favorites->set_text(0,"Favorites:"); + favorites->set_selectable(0,false); + Vector<String> faves = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<faves.size();i++) { + if (!faves[i].begins_with("res://")) + continue; + + TreeItem *ti = tree->create_item(favorites); + String fv = faves[i]; + if (fv=="res://") + ti->set_text(0,"/"); + else + ti->set_text(0,faves[i].get_file()); + ti->set_icon(0,get_icon("Folder","EditorIcons")); + ti->set_selectable(0,true); + ti->set_metadata(0,faves[i]); + } + + _create_tree(root,EditorFileSystem::get_singleton()->get_filesystem()); updating_tree=false; } @@ -117,68 +153,192 @@ void ScenesDock::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { + if (initialized) + return; + initialized=false; - EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"_update_tree"); + EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"_fs_changed"); button_reload->set_icon( get_icon("Reload","EditorIcons")); button_favorite->set_icon( get_icon("Favorites","EditorIcons")); + button_fav_up->set_icon( get_icon("MoveUp","EditorIcons")); + button_fav_down->set_icon( get_icon("MoveDown","EditorIcons")); button_instance->set_icon( get_icon("Add","EditorIcons")); button_open->set_icon( get_icon("Folder","EditorIcons")); + button_back->set_icon( get_icon("Filesystem","EditorIcons")); + display_mode->set_icon( get_icon("FileList","EditorIcons")); + display_mode->connect("pressed",this,"_change_file_display"); + file_options->set_icon( get_icon("Tools","EditorIcons")); + files->connect("item_activated",this,"_select_file"); + button_hist_next->connect("pressed",this,"_fw_history"); + button_hist_prev->connect("pressed",this,"_bw_history"); - String path = Globals::get_singleton()->get_resource_path()+"/favorites.cfg"; - FileAccess *f=FileAccess::open(path,FileAccess::READ); - if (f) { + button_hist_next->set_icon( get_icon("Forward","EditorIcons")); + button_hist_prev->set_icon( get_icon("Back","EditorIcons")); + file_options->get_popup()->connect("item_pressed",this,"_file_option"); - String l = f->get_line(); - while(l!="") { - favorites.insert(l); - l = f->get_line(); - - } + button_back->connect("pressed",this,"_go_to_tree",varray(),CONNECT_DEFERRED); + current_path->connect("text_entered",this,"_go_to_dir"); + _update_tree(); //maybe it finished already - f->close(); - memdelete(f); + if (EditorFileSystem::get_singleton()->is_scanning()) { + _set_scannig_mode(); } - - - _update_tree(); //maybe it finished already + } break; + case NOTIFICATION_PROCESS: { + if (EditorFileSystem::get_singleton()->is_scanning()) { + scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100); + } } break; case NOTIFICATION_EXIT_TREE: { } break; - case NOTIFICATION_PROCESS: { - } break; } } -void ScenesDock::_favorite_toggled() { - if (updating_tree) + + +void ScenesDock::_dir_selected() { + + TreeItem *ti = tree->get_selected(); + if (!ti) return; + String dir = ti->get_metadata(0); + bool found=false; + Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<favorites.size();i++) { + + if (favorites[i]==dir) { + found=true; + break; + } + } + + + button_favorite->set_pressed(found); + if (ti->get_parent() && ti->get_parent()->get_parent()==tree->get_root() && !ti->get_parent()->get_prev()) { + + //a favorite!!! + button_fav_up->set_disabled(!ti->get_prev()); + button_fav_down->set_disabled(!ti->get_next()); + } else { + button_fav_up->set_disabled(true); + button_fav_down->set_disabled(true); + + } +} + +void ScenesDock::_fav_up_pressed() { TreeItem *sel = tree->get_selected(); if (!sel) - return; //? + return ; - bool faved = sel->is_checked(0); - String path = sel->get_metadata(0); - if (faved) - favorites.insert(path); - else - favorites.erase(path); + if (!sel->get_prev()) + return; + + String sw = sel->get_prev()->get_metadata(0); + String txt = sel->get_metadata(0); + + Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs(); + + int a_idx=favorited.find(sw); + int b_idx=favorited.find(txt); + + if (a_idx==-1 || b_idx==-1) + return; + SWAP(favorited[a_idx],favorited[b_idx]); + + EditorSettings::get_singleton()->set_favorite_dirs(favorited); + + _update_tree(); - timer->start(); + if (!tree->get_root() || !tree->get_root()->get_children() || !tree->get_root()->get_children()->get_children()) + return; + sel = tree->get_root()->get_children()->get_children(); + while(sel) { + String t = sel->get_metadata(0); + if (t==txt) { + sel->select(0); + return; + } + sel=sel->get_next(); + } } -void ScenesDock::_favorites_toggled(bool p_toggled) { +void ScenesDock::_fav_down_pressed() { + + TreeItem *sel = tree->get_selected(); + if (!sel) + return ; + + if (!sel->get_next()) + return; + + String sw = sel->get_next()->get_metadata(0); + String txt = sel->get_metadata(0); + + Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs(); + + int a_idx=favorited.find(sw); + int b_idx=favorited.find(txt); + + if (a_idx==-1 || b_idx==-1) + return; + SWAP(favorited[a_idx],favorited[b_idx]); + + EditorSettings::get_singleton()->set_favorite_dirs(favorited); _update_tree(); + + if (!tree->get_root() || !tree->get_root()->get_children() || !tree->get_root()->get_children()->get_children()) + return; + sel = tree->get_root()->get_children()->get_children(); + while(sel) { + + String t = sel->get_metadata(0); + if (t==txt) { + sel->select(0); + return; + } + sel=sel->get_next(); + } +} + +void ScenesDock::_favorites_pressed() { + + TreeItem *sel = tree->get_selected(); + if (!sel) + return ; + String dir = sel->get_metadata(0); + + int idx = -1; + Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<favorites.size();i++) { + + if (favorites[i]==dir) { + idx=i; + break; + } + } + + if (button_favorite->is_pressed() && idx==-1) { + favorites.push_back(dir); + EditorSettings::get_singleton()->set_favorite_dirs(favorites); + _update_tree(); + } else if (!button_favorite->is_pressed() && idx!=-1) { + favorites.remove(idx); + EditorSettings::get_singleton()->set_favorite_dirs(favorites); + _update_tree(); + } + } String ScenesDock::get_selected_path() const { @@ -199,65 +359,712 @@ void ScenesDock::_instance_pressed() { emit_signal("instance",path); } -void ScenesDock::_open_pressed(){ +void ScenesDock::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) { - TreeItem *sel = tree->get_selected(); - if (!sel) { + if (p_preview.is_valid() && path==p_path.get_base_dir()) { + + int idx=p_udata; + if (idx>=files->get_item_count()) + return; + String fpath = files->get_item_metadata(idx); + if (fpath!=p_path) + return; + files->set_item_icon(idx,p_preview); + + } + +} + +void ScenesDock::_change_file_display() { + + if (display_mode->is_pressed()) { + display_mode->set_icon( get_icon("FileThumbnail","EditorIcons")); + + } else { + display_mode->set_icon( get_icon("FileList","EditorIcons")); + } + + _update_files(true); +} + +void ScenesDock::_update_files(bool p_keep_selection) { + + Set<String> cselection; + + if (p_keep_selection) { + + for(int i=0;i<files->get_item_count();i++) { + + if (files->is_selected(i)) + cselection.insert(files->get_item_text(i)); + } + } + + files->clear(); + + EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_path(path); + if (!efd) return; + + int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size"); + Ref<Texture> folder_thumbnail; + Ref<Texture> file_thumbnail; + + bool use_thumbnails=!display_mode->is_pressed(); + + if (use_thumbnails) { //thumbnails + + files->set_max_columns(0); + files->set_icon_mode(ItemList::ICON_MODE_TOP); + files->set_fixed_column_width(thumbnail_size*3/2); + files->set_max_text_lines(2); + files->set_min_icon_size(Size2(thumbnail_size,thumbnail_size)); + + if (!has_icon("ResizedFolder","EditorIcons")) { + Ref<ImageTexture> folder = get_icon("FolderBig","EditorIcons"); + Image img = folder->get_data(); + 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("ResizedFolder","EditorIcons",resized_folder); + } + + folder_thumbnail = get_icon("ResizedFolder","EditorIcons"); + + if (!has_icon("ResizedFile","EditorIcons")) { + Ref<ImageTexture> file = get_icon("FileBig","EditorIcons"); + Image img = file->get_data(); + 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("ResizedFile","EditorIcons",resized_file); + } + + file_thumbnail = get_icon("ResizedFile","EditorIcons"); + + } else { + + files->set_icon_mode(ItemList::ICON_MODE_LEFT); + files->set_max_columns(1); + files->set_max_text_lines(1); + files->set_fixed_column_width(0); + files->set_min_icon_size(Size2()); + } - String path = sel->get_metadata(0); - if (ResourceLoader::get_resource_type(path)=="PackedScene") { - editor->open_request(path); + if (path!="res://") { + + if (use_thumbnails) { + files->add_item("..",folder_thumbnail,true); + } else { + files->add_item("..",get_icon("folder","FileDialog"),true); + } + + String bd = path.get_base_dir(); + if (bd!="res://" && !bd.ends_with("/")) + bd+="/"; + + files->set_item_metadata(files->get_item_count()-1,bd); + } + + for(int i=0;i<efd->get_subdir_count();i++) { + + String dname=efd->get_subdir(i)->get_name(); + + + if (use_thumbnails) { + files->add_item(dname,folder_thumbnail,true); + } else { + files->add_item(dname,get_icon("folder","FileDialog"),true); + } + + files->set_item_metadata(files->get_item_count()-1,path.plus_file(dname)+"/"); + + if (cselection.has(dname)) + files->select(files->get_item_count()-1,false); + } + + for(int i=0;i<efd->get_file_count();i++) { + + String fname=efd->get_file(i); + String fp = path.plus_file(fname); + + + String type = efd->get_file_type(i); + Ref<Texture> type_icon; + + if (has_icon(type,"EditorIcons")) { + type_icon=get_icon(type,"EditorIcons"); + } else { + type_icon=get_icon("Object","EditorIcons"); + } + + if (use_thumbnails) { + files->add_item(fname,file_thumbnail,true); + files->set_item_metadata(files->get_item_count()-1,fp); + files->set_item_tag_icon(files->get_item_count()-1,type_icon); + EditorResourcePreview::get_singleton()->queue_resource_preview(fp,this,"_thumbnail_done",files->get_item_count()-1); + } else { + files->add_item(fname,type_icon,true); + files->set_item_metadata(files->get_item_count()-1,fp); + + } + + if (cselection.has(fname)) + files->select(files->get_item_count()-1,false); + + } + + +} + +void ScenesDock::_select_file(int p_idx) { + + files->select(p_idx,true); + _open_pressed(); +} + +void ScenesDock::_go_to_tree() { + + tree->show(); + files->hide(); + path_hb->hide(); + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + button_favorite->show(); + button_fav_up->show(); + button_fav_down->show(); + button_open->hide(); + button_instance->hide(); + button_open->hide(); + file_options->hide(); + tree_mode=true; +} + +void ScenesDock::_go_to_dir(const String& p_dir){ + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da->change_dir(p_dir)==OK) { + path=da->get_current_dir(); + _update_files(false); + } + current_path->set_text(path); + memdelete(da); + + +} +void ScenesDock::_fs_changed() { + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + scanning_vb->hide(); + + if (tree_mode) { + + tree->show(); + button_favorite->show(); + button_fav_up->show(); + button_fav_down->show(); + _update_tree(); + } else { + files->show(); + path_hb->show(); + button_instance->show(); + button_open->show(); + file_options->show(); + _update_files(true); + } + + set_process(false); +} + +void ScenesDock::_set_scannig_mode() { + + tree->hide(); + button_favorite->hide(); + button_fav_up->hide(); + button_fav_down->hide(); + button_instance->hide(); + button_open->hide(); + file_options->hide(); + button_hist_prev->set_disabled(true); + button_hist_next->set_disabled(true); + scanning_vb->show(); + path_hb->hide(); + files->hide(); + set_process(true); + if (EditorFileSystem::get_singleton()->is_scanning()) { + scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100); + } else { + scanning_progress->set_val(0); + } + +} + +void ScenesDock::_fw_history() { + + if (history_pos<history.size()-1) + history_pos++; + + path=history[history_pos]; + + if (tree_mode) { + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + } else { + _update_files(false); + current_path->set_text(path); + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + +void ScenesDock::_bw_history() { + + if (history_pos>0) + history_pos--; + + path=history[history_pos]; + + if (tree_mode) { + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); } else { + _update_files(false); + current_path->set_text(path); + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + +void ScenesDock::_push_to_history() { - /* + history.resize(history_pos+1); + if (history[history_pos]!=path) { + history.push_back(path); + history_pos++; + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + + +void ScenesDock::_find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files) { - RES res = ResourceLoader::load(path); - if (res.is_null()) { + for(int i=0;i<efsd->get_subdir_count();i++) { + _find_inside_move_files(efsd->get_subdir(i),files); + } + for(int i=0;i<efsd->get_file_count();i++) { + files.push_back(efsd->get_file_path(i)); + } + +} +void ScenesDock::_find_remaps(EditorFileSystemDirectory *efsd,Map<String,String> &renames,List<String>& to_remaps) { + for(int i=0;i<efsd->get_subdir_count();i++) { + _find_remaps(efsd->get_subdir(i),renames,to_remaps); + } + for(int i=0;i<efsd->get_file_count();i++) { + Vector<String> deps=efsd->get_file_deps(i); + for(int j=0;j<deps.size();j++) { + if (renames.has(deps[j])) { + to_remaps.push_back(efsd->get_file_path(i)); + break; + } + } + } +} + + +void ScenesDock::_rename_operation(const String& p_to_path) { + + if (move_files[0]==p_to_path) { + EditorNode::get_singleton()->show_warning("Same source and destination files, doing nothing."); + return; + } + if (FileAccess::exists(p_to_path)) { + EditorNode::get_singleton()->show_warning("Target file exists, can't overwrite. Delete first."); + return; + } + + Map<String,String> renames; + renames[move_files[0]]=p_to_path; + + List<String> remap; + + _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(),renames,remap); + print_line("found files to remap: "+itos(remap.size())); + + //perform remaps + for(List<String>::Element *E=remap.front();E;E=E->next()) { + + Error err = ResourceLoader::rename_dependencies(E->get(),renames); + print_line("remapping: "+E->get()); + + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n"+E->get()+"\n"); + } + } + + //finally, perform moves + + DirAccess *da=DirAccess::create(DirAccess::ACCESS_RESOURCES); + + Error err = da->rename(move_files[0],p_to_path); + print_line("moving file "+move_files[0]+" to "+p_to_path); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving file:\n"+move_files[0]+"\n"); + } + + //rescan everything + memdelete(da); + print_line("call rescan!"); + _rescan(); +} + + +void ScenesDock::_move_operation(const String& p_to_path) { + + if (p_to_path==path) { + EditorNode::get_singleton()->show_warning("Same source and destination paths, doing nothing."); + return; + } + + //find files inside dirs to be moved + + Vector<String> inside_files; + + for(int i=0;i<move_dirs.size();i++) { + if (p_to_path.begins_with(move_dirs[i])) { + EditorNode::get_singleton()->show_warning("Can't move directories to within themselves"); return; - }*/ + } - editor->load_resource(path); + EditorFileSystemDirectory *efsd=EditorFileSystem::get_singleton()->get_path(move_dirs[i]); + if (!efsd) + continue; + _find_inside_move_files(efsd,inside_files); } -// emit_signal("open",path); + //make list of remaps + Map<String,String> renames; + String repfrom=path=="res://"?path:String(path+"/"); + String repto=p_to_path=="res://"?p_to_path:String(p_to_path+"/"); + + for(int i=0;i<move_files.size();i++) { + renames[move_files[i]]=move_files[i].replace_first(repfrom,repto); + print_line("move file "+move_files[i]+" -> "+renames[move_files[i]]); + } + for(int i=0;i<inside_files.size();i++) { + renames[inside_files[i]]=inside_files[i].replace_first(repfrom,repto); + print_line("inside file "+inside_files[i]+" -> "+renames[inside_files[i]]); + } + + //make list of files that will be run the remapping + List<String> remap; + _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(),renames,remap); + print_line("found files to remap: "+itos(remap.size())); + + //perform remaps + for(List<String>::Element *E=remap.front();E;E=E->next()) { + + Error err = ResourceLoader::rename_dependencies(E->get(),renames); + print_line("remapping: "+E->get()); + + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n"+E->get()+"\n"); + } + } + + //finally, perform moves + + DirAccess *da=DirAccess::create(DirAccess::ACCESS_RESOURCES); + + for(int i=0;i<move_files.size();i++) { + + String to = move_files[i].replace_first(repfrom,repto); + Error err = da->rename(move_files[i],to); + print_line("moving file "+move_files[i]+" to "+to); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving file:\n"+move_files[i]+"\n"); + } + } + + for(int i=0;i<move_dirs.size();i++) { + + String to = p_to_path.plus_file(move_dirs[i].get_file()); + Error err = da->rename(move_dirs[i],to); + print_line("moving dir "+move_dirs[i]+" to "+to); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving dir:\n"+move_dirs[i]+"\n"); + } + } + + memdelete(da); + //rescan everything + print_line("call rescan!"); + _rescan(); + +} + +void ScenesDock::_file_option(int p_option) { + + switch(p_option) { + + case FILE_DEPENDENCIES: { + + int idx = files->get_current(); + if (idx<0 || idx>=files->get_item_count()) + break; + String path = files->get_item_metadata(idx); + deps_editor->edit(path); + } break; + case FILE_OWNERS: { + + int idx = files->get_current(); + if (idx<0 || idx>=files->get_item_count()) + break; + String path = files->get_item_metadata(idx); + owners_editor->show(path); + } break; + case FILE_MOVE: { + + move_dirs.clear();; + move_files.clear(); + + for(int i=0;i<files->get_item_count();i++) { + + String path = files->get_item_metadata(i); + if (!files->is_selected(i)) + continue; + + if (files->get_item_text(i)=="..") { + EditorNode::get_singleton()->show_warning("Can't operate on '..'"); + return; + } + + if (path.ends_with("/")) { + move_dirs.push_back(path.substr(0,path.length()-1)); + } else { + move_files.push_back(path); + } + } + + + if (move_dirs.empty() && move_files.size()==1) { + + rename_dialog->clear_filters(); + rename_dialog->add_filter("*."+move_files[0].extension()); + rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + rename_dialog->set_current_path(move_files[0]); + rename_dialog->popup_centered_ratio(); + rename_dialog->set_title("Pick New Name and Location For: "+move_files[0].get_file()); + + + } else { + //just move + move_dialog->popup_centered_ratio(); + } + + + } break; + case FILE_REMOVE: { + + Vector<String> torem; + + for(int i=0;i<files->get_item_count();i++) { + + String path = files->get_item_metadata(i); + if (path.ends_with("/") || !files->is_selected(i)) + continue; + torem.push_back(path); + } + + if (torem.empty()) { + EditorNode::get_singleton()->show_warning("No files selected!"); + break; + } + + remove_dialog->show(torem); + //1) find if used + //2) warn + + } break; + case FILE_INFO: { + + } break; + + } } -void ScenesDock::_save_favorites() { +void ScenesDock::_open_pressed(){ + + + if (tree_mode) { + + TreeItem *sel = tree->get_selected(); + if (!sel) { + return; + } + path = sel->get_metadata(0); + /*if (path!="res://" && path.ends_with("/")) { + path=path.substr(0,path.length()-1); + }*/ + + tree_mode=false; + + tree->hide(); + files->show(); + path_hb->show(); + button_favorite->hide(); + button_fav_up->hide(); + button_fav_down->hide(); + button_instance->show(); + button_open->show(); + file_options->show(); + + _update_files(false); - String path = Globals::get_singleton()->get_resource_path()+"/favorites.cfg"; - FileAccess *f=FileAccess::open(path,FileAccess::WRITE); - ERR_FAIL_COND(!f); - for(Set<String>::Element *E=favorites.front();E;E=E->next() ) { + current_path->set_text(path); - CharString utf8f = E->get().utf8(); - f->store_buffer((const uint8_t*)utf8f.get_data(),utf8f.length()); - f->store_8('\n'); + _push_to_history(); + + + } else { + + int idx=-1; + for(int i=0;i<files->get_item_count();i++) { + if (files->is_selected(i)) { + idx=i; + break; + } + } + + if (idx<0) + return; + + + + String path = files->get_item_metadata(idx); + + if (path.ends_with("/")) { + if (path!="res://") { + path=path.substr(0,path.length()-1); + } + this->path=path; + _update_files(false); + current_path->set_text(path); + _push_to_history(); + } else { + + if (ResourceLoader::get_resource_type(path)=="PackedScene") { + + editor->open_request(path); + } else { + + editor->load_resource(path); + } + } } - f->close(); - memdelete(f); +// emit_signal("open",path); + } + void ScenesDock::_rescan() { + _set_scannig_mode(); EditorFileSystem::get_singleton()->scan(); + +} + +void ScenesDock::fix_dependencies(const String& p_for_file) { + deps_editor->edit(p_for_file); +} + +void ScenesDock::open(const String& p_path) { + + + String npath; + String nfile; + + if (p_path.ends_with("/")) { + + if (p_path!="res://") + npath=p_path.substr(0,p_path.length()-1); + else + npath="res://"; + } else { + nfile=p_path.get_file(); + npath=p_path.get_base_dir(); + } + + path=npath; + + if (tree_mode && nfile=="") { + _update_tree(); + tree->grab_focus(); + tree->call_deferred("ensure_cursor_is_visible"); + _push_to_history(); + return; + } else if (tree_mode){ + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + _open_pressed(); + current_path->set_text(path); + } else { + _update_files(false); + _push_to_history(); + } + + for(int i=0;i<files->get_item_count();i++) { + + String md = files->get_item_metadata(i); + if (md==p_path) { + files->select(i,true); + files->ensure_current_is_visible(); + break; + } + } + } void ScenesDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_update_tree"),&ScenesDock::_update_tree); ObjectTypeDB::bind_method(_MD("_rescan"),&ScenesDock::_rescan); - ObjectTypeDB::bind_method(_MD("_favorites_toggled"),&ScenesDock::_favorites_toggled); - ObjectTypeDB::bind_method(_MD("_favorite_toggled"),&ScenesDock::_favorite_toggled); + ObjectTypeDB::bind_method(_MD("_favorites_pressed"),&ScenesDock::_favorites_pressed); ObjectTypeDB::bind_method(_MD("_instance_pressed"),&ScenesDock::_instance_pressed); ObjectTypeDB::bind_method(_MD("_open_pressed"),&ScenesDock::_open_pressed); - ObjectTypeDB::bind_method(_MD("_save_favorites"),&ScenesDock::_save_favorites); + + ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&ScenesDock::_thumbnail_done); + ObjectTypeDB::bind_method(_MD("_select_file"), &ScenesDock::_select_file); + ObjectTypeDB::bind_method(_MD("_go_to_tree"), &ScenesDock::_go_to_tree); + ObjectTypeDB::bind_method(_MD("_go_to_dir"), &ScenesDock::_go_to_dir); + ObjectTypeDB::bind_method(_MD("_change_file_display"), &ScenesDock::_change_file_display); + ObjectTypeDB::bind_method(_MD("_fw_history"), &ScenesDock::_fw_history); + ObjectTypeDB::bind_method(_MD("_bw_history"), &ScenesDock::_bw_history); + ObjectTypeDB::bind_method(_MD("_fs_changed"), &ScenesDock::_fs_changed); + ObjectTypeDB::bind_method(_MD("_dir_selected"), &ScenesDock::_dir_selected); + ObjectTypeDB::bind_method(_MD("_fav_up_pressed"), &ScenesDock::_fav_up_pressed); + ObjectTypeDB::bind_method(_MD("_fav_down_pressed"), &ScenesDock::_fav_down_pressed); + ObjectTypeDB::bind_method(_MD("_file_option"), &ScenesDock::_file_option); + ObjectTypeDB::bind_method(_MD("_move_operation"), &ScenesDock::_move_operation); + ObjectTypeDB::bind_method(_MD("_rename_operation"), &ScenesDock::_rename_operation); ADD_SIGNAL(MethodInfo("instance")); ADD_SIGNAL(MethodInfo("open")); @@ -271,153 +1078,156 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { HBoxContainer *toolbar_hbc = memnew( HBoxContainer ); add_child(toolbar_hbc); + button_hist_prev = memnew( ToolButton ); + toolbar_hbc->add_child(button_hist_prev); + button_hist_prev->set_disabled(true); + button_hist_prev->set_tooltip("Previous Directory"); + + button_hist_next = memnew( ToolButton ); + toolbar_hbc->add_child(button_hist_next); + button_hist_next->set_disabled(true); + button_hist_prev->set_focus_mode(FOCUS_NONE); + button_hist_next->set_focus_mode(FOCUS_NONE); + button_hist_next->set_tooltip("Next Directory"); + button_reload = memnew( Button ); button_reload->set_flat(true); button_reload->connect("pressed",this,"_rescan"); toolbar_hbc->add_child(button_reload); + button_reload->set_focus_mode(FOCUS_NONE); + button_reload->set_tooltip("Re-Scan Filesystem"); + + toolbar_hbc->add_spacer(); + + button_fav_up = memnew( ToolButton ); + button_fav_up->set_flat(true); + toolbar_hbc->add_child(button_fav_up); + button_fav_up->set_disabled(true); + button_fav_up->connect("pressed",this,"_fav_up_pressed"); + button_fav_up->set_tooltip("Move Favorite Up"); + + button_fav_down = memnew( ToolButton ); + button_fav_down->set_flat(true); + toolbar_hbc->add_child(button_fav_down); + button_fav_down->set_disabled(true); + button_fav_down->connect("pressed",this,"_fav_down_pressed"); + button_fav_down->set_tooltip("Move Favorite Down"); button_favorite = memnew( Button ); button_favorite->set_flat(true); button_favorite->set_toggle_mode(true); - button_favorite->connect("toggled",this,"_favorites_toggled"); + button_favorite->connect("pressed",this,"_favorites_pressed"); toolbar_hbc->add_child(button_favorite); + button_favorite->set_tooltip("Toggle folder status as Favorite"); + + button_favorite->set_focus_mode(FOCUS_NONE); + button_fav_up->set_focus_mode(FOCUS_NONE); + button_fav_down->set_focus_mode(FOCUS_NONE); - toolbar_hbc->add_spacer(); button_open = memnew( Button ); button_open->set_flat(true); button_open->connect("pressed",this,"_open_pressed"); toolbar_hbc->add_child(button_open); + button_open->hide(); + button_open->set_focus_mode(FOCUS_NONE); + button_open->set_tooltip("Open the selected file.\nOpen as scene if a scene, or as resource otherwise."); + button_instance = memnew( Button ); button_instance->set_flat(true); button_instance->connect("pressed",this,"_instance_pressed"); toolbar_hbc->add_child(button_instance); + button_instance->hide(); + button_instance->set_focus_mode(FOCUS_NONE); + button_instance->set_tooltip("Instance the selected scene(s) as child of the selected node."); + + + file_options = memnew( MenuButton ); + toolbar_hbc->add_child(file_options); + file_options->get_popup()->add_item("Rename or Move",FILE_MOVE); + file_options->get_popup()->add_item("Delete",FILE_REMOVE); + file_options->get_popup()->add_separator(); + file_options->get_popup()->add_item("Edit Dependencies",FILE_DEPENDENCIES); + file_options->get_popup()->add_item("View Owners",FILE_OWNERS); + //file_options->get_popup()->add_item("Info",FILE_INFO); + file_options->hide(); + file_options->set_focus_mode(FOCUS_NONE); + file_options->set_tooltip("Miscenaneous options related to resources on disk."); tree = memnew( Tree ); - tree_filter=memnew( ScenesDockFilter() ); - tree_filter->connect("filter_changed", this, "_update_tree"); - add_child(tree_filter); + + tree->set_hide_root(true); add_child(tree); + tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->connect("item_edited",this,"_favorite_toggled"); tree->connect("item_activated",this,"_open_pressed"); - - timer = memnew( Timer ); - timer->set_one_shot(true); - timer->set_wait_time(2); - timer->connect("timeout",this,"_save_favorites"); - add_child(timer); - + tree->connect("cell_selected",this,"_dir_selected"); + + files = memnew( ItemList ); + files->set_v_size_flags(SIZE_EXPAND_FILL); + files->set_select_mode(ItemList::SELECT_MULTI); + + path_hb = memnew( HBoxContainer ); + button_back = memnew( ToolButton ); + path_hb->add_child(button_back); + current_path=memnew( LineEdit ); + current_path->set_h_size_flags(SIZE_EXPAND_FILL); + path_hb->add_child(current_path); + display_mode = memnew( ToolButton ); + path_hb->add_child(display_mode); + display_mode->set_toggle_mode(true); + add_child(path_hb); + path_hb->hide(); + + + add_child(files); + files->hide(); + + scanning_vb = memnew( VBoxContainer ); + Label *slabel = memnew( Label ); + slabel->set_text("Scanning Files,\nPlease Wait.."); + slabel->set_align(Label::ALIGN_CENTER); + scanning_vb->add_child(slabel); + scanning_progress = memnew( ProgressBar ); + scanning_vb->add_child(scanning_progress); + add_child(scanning_vb); + scanning_vb->hide(); + + + + deps_editor = memnew( DependencyEditor ); + add_child(deps_editor); + + owners_editor = memnew( DependencyEditorOwners); + add_child(owners_editor); + + remove_dialog = memnew( DependencyRemoveDialog); + add_child(remove_dialog); + + move_dialog = memnew( EditorDirDialog ); + add_child(move_dialog); + move_dialog->connect("dir_selected",this,"_move_operation"); + move_dialog->get_ok()->set_text("Move"); + + rename_dialog = memnew( EditorFileDialog ); + rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + rename_dialog->connect("file_selected",this,"_rename_operation"); + add_child(rename_dialog); updating_tree=false; + initialized=false; -} - -ScenesDock::~ScenesDock() { - -} - -void ScenesDockFilter::_setup_filters() { - - filter_option->clear(); - filter_option->add_item("Path"); - filter_option->add_item("Name"); - filter_option->add_item("Folder"); -#if 0 - List<String> extensions; - ResourceLoader::get_recognized_extensions_for_type("",&extensions); - - file_filter->add_item("All Files (*)"); - filters.push_back("*"); - - List<String> filter_texts; - for(int i=0;i<extensions.size();i++) { - filter_texts.push_back("*."+extensions[i]+" ; "+extensions[i].to_upper()); - filters.push_back(extensions[i]); - } - for(int i=0;i<filter_texts.size();i++) { - - String flt=filter_texts[i].get_slice(";",0).strip_edges(); - String desc=filter_texts[i].get_slice(";",1).strip_edges(); - if (desc.length()) - file_filter->add_item(desc+" ( "+flt+" )"); - else - file_filter->add_item("( "+flt+" )"); - } -#endif -} - -void ScenesDockFilter::_command(int p_command) { - switch (p_command) { - - case CMD_CLEAR_FILTER: { - if (search_box->get_text()!="") { - search_box->clear(); - emit_signal("filter_changed"); - } - }break; - } -} - -void ScenesDockFilter::_search_text_changed(const String &p_newtext) { - emit_signal("filter_changed"); -} - -String ScenesDockFilter::get_search_term() { - return search_box->get_text().strip_edges(); -} - -ScenesDockFilter::FilterOption ScenesDockFilter::get_file_filter() { - return _current_filter; -} - -void ScenesDockFilter::_file_filter_selected(int p_idx) { - FilterOption selected = (FilterOption)(filter_option->get_selected()); - if (_current_filter != selected ) { - _current_filter = selected; - emit_signal("filter_changed"); - } -} - -void ScenesDockFilter::_notification(int p_what) { - switch(p_what) { - case NOTIFICATION_ENTER_TREE: { - clear_search_button->set_icon(get_icon("CloseHover","EditorIcons")); - } break; - } -} - -void ScenesDockFilter::_bind_methods() { + history.push_back("res://"); + history_pos=0; + tree_mode=true; - ObjectTypeDB::bind_method(_MD("_command"),&ScenesDockFilter::_command); - ObjectTypeDB::bind_method(_MD("_search_text_changed"), &ScenesDockFilter::_search_text_changed); - ObjectTypeDB::bind_method(_MD("_file_filter_selected"), &ScenesDockFilter::_file_filter_selected); - ADD_SIGNAL( MethodInfo("filter_changed") ); } -ScenesDockFilter::ScenesDockFilter() { - - _current_filter = FILTER_PATH; - - filter_option = memnew( OptionButton ); - filter_option->set_custom_minimum_size(Size2(60,10)); - filter_option->set_clip_text(true); - filter_option->connect("item_selected", this, "_file_filter_selected"); - add_child(filter_option); - - _setup_filters(); - - search_box = memnew( LineEdit ); - search_box->connect("text_changed",this,"_search_text_changed"); - search_box->set_h_size_flags(SIZE_EXPAND_FILL); - add_child(search_box); - - clear_search_button = memnew( ToolButton ); - clear_search_button->connect("pressed",this,"_command",make_binds(CMD_CLEAR_FILTER)); - add_child(clear_search_button); +ScenesDock::~ScenesDock() { } diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h index de7ab51edc..d045124bf7 100644 --- a/tools/editor/scenes_dock.h +++ b/tools/editor/scenes_dock.h @@ -36,40 +36,112 @@ #include "scene/gui/tool_button.h" #include "scene/gui/option_button.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/item_list.h" +#include "scene/gui/progress_bar.h" + #include "os/dir_access.h" #include "os/thread.h" #include "editor_file_system.h" - +#include "editor_dir_dialog.h" +#include "dependency_editor.h" class EditorNode; -class ScenesDockFilter; + class ScenesDock : public VBoxContainer { OBJ_TYPE( ScenesDock, VBoxContainer ); + enum FileMenu { + FILE_DEPENDENCIES, + FILE_OWNERS, + FILE_MOVE, + FILE_REMOVE, + FILE_REIMPORT, + FILE_INFO + }; + + + VBoxContainer *scanning_vb; + ProgressBar *scanning_progress; + EditorNode *editor; Set<String> favorites; Button *button_reload; Button *button_instance; Button *button_favorite; + Button *button_fav_up; + Button *button_fav_down; Button *button_open; - Timer *timer; + Button *button_back; + Button *display_mode; + Button *button_hist_next; + Button *button_hist_prev; + LineEdit *current_path; + HBoxContainer *path_hb; + + MenuButton *file_options; + + + DependencyEditor *deps_editor; + DependencyEditorOwners *owners_editor; + DependencyRemoveDialog *remove_dialog; + + EditorDirDialog *move_dialog; + EditorFileDialog *rename_dialog; - ScenesDockFilter *tree_filter; + Vector<String> move_dirs; + Vector<String> move_files; + + + Vector<String> history; + int history_pos; + + String path; + + bool initialized; bool updating_tree; - Tree * tree; + Tree * tree; //directories + ItemList *files; + + bool tree_mode; + + void _go_to_tree(); + void _go_to_dir(const String& p_dir); + void _select_file(int p_idx); + bool _create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir); + void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata); + void _find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files); + void _find_remaps(EditorFileSystemDirectory *efsd,Map<String,String> &renames,List<String>& to_remaps); + + void _rename_operation(const String& p_to_path); + void _move_operation(const String& p_to_path); + + + void _file_option(int p_option); + void _update_files(bool p_keep_selection); + void _change_file_display(); + void _fs_changed(); + void _fw_history(); + void _bw_history(); + void _push_to_history(); + + void _fav_up_pressed(); + void _fav_down_pressed(); + void _dir_selected(); void _update_tree(); void _rescan(); - void _favorites_toggled(bool); - void _favorite_toggled(); + void _set_scannig_mode(); + + void _favorites_pressed(); void _instance_pressed(); void _open_pressed(); - void _save_favorites(); + protected: void _notification(int p_what); @@ -77,48 +149,14 @@ protected: public: String get_selected_path() const; + void open(const String& p_path); + + void fix_dependencies(const String& p_for_file); + ScenesDock(EditorNode *p_editor); ~ScenesDock(); }; -class ScenesDockFilter : public HBoxContainer { - - OBJ_TYPE( ScenesDockFilter, HBoxContainer ); - -private: - friend class ScenesDock; - - enum Command { - CMD_CLEAR_FILTER, - }; - - Tree *tree; - OptionButton *filter_option; - LineEdit *search_box; - ToolButton *clear_search_button; - - enum FilterOption { - FILTER_PATH, // NAME or Folder - FILTER_NAME, - FILTER_FOLDER, - }; - FilterOption _current_filter; - //Vector<String> filters; - - void _command(int p_command); - void _search_text_changed(const String& p_newtext); - void _setup_filters(); - void _file_filter_selected(int p_idx); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - String get_search_term(); - FilterOption get_file_filter(); - ScenesDockFilter(); -}; #endif // SCENES_DOCK_H |