diff options
Diffstat (limited to 'editor')
44 files changed, 1083 insertions, 297 deletions
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h index 9b0aca67d5..0cc153945d 100644 --- a/editor/dependency_editor.h +++ b/editor/dependency_editor.h @@ -35,6 +35,7 @@ #include "scene/gui/tab_container.h" #include "scene/gui/tree.h" +class EditorFileDialog; class EditorFileSystemDirectory; class EditorNode; diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 3a72f8e569..0bb059f425 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -235,7 +235,7 @@ void DocData::generate(bool p_basic_types) { ClassDB::get_property_list(name, &properties, true); for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY) + if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_INTERNAL) continue; PropertyDoc prop; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 8c8d9c4c79..3f618c3199 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -743,6 +743,18 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & custom_map["path_remap/remapped_paths"] = path_remaps; } + // Store icon and splash images directly, they need to bypass the import system and be loaded as images + String icon = ProjectSettings::get_singleton()->get("application/config/icon"); + String splash = ProjectSettings::get_singleton()->get("application/boot_splash/image"); + if (icon != String() && FileAccess::exists(icon)) { + Vector<uint8_t> array = FileAccess::get_file_as_array(icon); + p_func(p_udata, icon, array, idx, total); + } + if (splash != String() && FileAccess::exists(splash)) { + Vector<uint8_t> array = FileAccess::get_file_as_array(splash); + p_func(p_udata, splash, array, idx, total); + } + String config_file = "project.binary"; String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); @@ -1249,6 +1261,7 @@ bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset, if (custom_debug_binary == "" && custom_release_binary == "") { if (!err.empty()) r_error = err; + r_missing_templates = !valid; return valid; } diff --git a/editor/editor_export.h b/editor/editor_export.h index 346c3b58e1..215a770a12 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -122,8 +122,9 @@ struct SharedObject { String path; Vector<String> tags; - SharedObject(const String &p_path, const Vector<String> &p_tags) - : path(p_path), tags(p_tags) { + SharedObject(const String &p_path, const Vector<String> &p_tags) : + path(p_path), + tags(p_tags) { } SharedObject() {} diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index eb5af2eaeb..eaa57fa46b 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -28,12 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "editor_file_dialog.h" - +#include "dependency_editor.h" #include "editor_resource_preview.h" #include "editor_scale.h" #include "editor_settings.h" #include "os/file_access.h" #include "os/keyboard.h" +#include "os/os.h" #include "print_string.h" #include "scene/gui/center_container.h" #include "scene/gui/label.h" @@ -159,6 +160,10 @@ void EditorFileDialog::_unhandled_input(const Ref<InputEvent> &p_event) { _make_dir(); handled = true; } + if (ED_IS_SHORTCUT("file_dialog/delete", p_event)) { + _delete_items(); + handled = true; + } if (ED_IS_SHORTCUT("file_dialog/focus_path", p_event)) { dir->grab_focus(); handled = true; @@ -512,6 +517,106 @@ void EditorFileDialog::_item_dc_selected(int p_item) { } } +void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p_pos) { + + // Right click on specific file(s) or folder(s). + item_menu->clear(); + item_menu->set_size(Size2(1, 1)); + + // Allow specific actions only on one item. + bool single_item_selected = item_list->get_selected_items().size() == 1; + + // Disallow deleting the .import folder, Godot kills a cat if you do and it is possibly a senseless novice action. + bool allow_delete = true; + for (int i = 0; i < item_list->get_item_count(); i++) { + if (!item_list->is_selected(i)) { + continue; + } + Dictionary item_meta = item_list->get_item_metadata(i); + if (item_meta["path"] == "res://.import") { + allow_delete = false; + break; + } + } + + if (single_item_selected) { + item_menu->add_icon_item(get_icon("CopyNodePath", "EditorIcons"), TTR("Copy Path"), ITEM_MENU_COPY_PATH); + } + if (allow_delete) { + item_menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete"), ITEM_MENU_DELETE, KEY_DELETE); + } + if (single_item_selected) { + item_menu->add_separator(); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + } + + if (item_menu->get_item_count() > 0) { + item_menu->set_position(item_list->get_global_position() + p_pos); + item_menu->popup(); + } +} + +void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) { + + // Right click on folder background. Deselect all files so that actions are applied on the current folder. + for (int i = 0; i < item_list->get_item_count(); i++) { + item_list->unselect(i); + } + + item_menu->clear(); + item_menu->set_size(Size2(1, 1)); + + if (can_create_dir) { + item_menu->add_icon_item(get_icon("folder", "FileDialog"), TTR("New Folder.."), ITEM_MENU_NEW_FOLDER, KEY_MASK_CMD | KEY_N); + } + item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5); + item_menu->add_separator(); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + + item_menu->set_position(item_list->get_global_position() + p_pos); + item_menu->popup(); +} + +void EditorFileDialog::_item_menu_id_pressed(int p_option) { + + switch (p_option) { + + case ITEM_MENU_COPY_PATH: { + Dictionary item_meta = item_list->get_item_metadata(item_list->get_current()); + OS::get_singleton()->set_clipboard(item_meta["path"]); + } break; + + case ITEM_MENU_DELETE: { + _delete_items(); + } break; + + case ITEM_MENU_REFRESH: { + invalidate(); + } break; + + case ITEM_MENU_NEW_FOLDER: { + _make_dir(); + } break; + + case ITEM_MENU_SHOW_IN_EXPLORER: { + String path; + int idx = item_list->get_current(); + if (idx == -1 || item_list->get_selected_items().size() == 0) { + // Folder background was clicked. Open this folder. + path = ProjectSettings::get_singleton()->globalize_path(dir_access->get_current_dir()); + } else { + // Specific item was clicked. Open folders directly, or the folder containing a selected file. + Dictionary item_meta = item_list->get_item_metadata(idx); + path = ProjectSettings::get_singleton()->globalize_path(item_meta["path"]); + if (!item_meta["dir"]) { + path = path.get_base_dir(); + } + } + OS::get_singleton()->shell_open(String("file://") + path); + } break; + } +} + bool EditorFileDialog::_is_open_should_be_disabled() { if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE) @@ -617,7 +722,7 @@ void EditorFileDialog::update_file_list() { Dictionary d; d["name"] = dir_name; - d["path"] = String(); + d["path"] = cdir.plus_file(dir_name); d["dir"] = true; item_list->set_item_metadata(item_list->get_item_count() - 1, d); @@ -657,8 +762,6 @@ void EditorFileDialog::update_file_list() { } } - String base_dir = dir_access->get_current_dir(); - while (!files.empty()) { bool match = patterns.empty(); @@ -679,7 +782,7 @@ void EditorFileDialog::update_file_list() { if (get_icon_func) { - Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get())); + Ref<Texture> icon = get_icon_func(cdir.plus_file(files.front()->get())); //ti->set_icon(0,icon); if (display_mode == DISPLAY_THUMBNAILS) { @@ -698,12 +801,11 @@ void EditorFileDialog::update_file_list() { Dictionary d; d["name"] = files.front()->get(); d["dir"] = false; - String fullpath = base_dir.plus_file(files.front()->get()); - + String fullpath = cdir.plus_file(files.front()->get()); if (display_mode == DISPLAY_THUMBNAILS) { EditorResourcePreview::get_singleton()->queue_resource_preview(fullpath, this, "_thumbnail_result", fullpath); } - d["path"] = base_dir.plus_file(files.front()->get()); + d["path"] = fullpath; //ti->set_metadata(0,d); item_list->set_item_metadata(item_list->get_item_count() - 1, d); @@ -723,7 +825,7 @@ void EditorFileDialog::update_file_list() { fav_down->set_disabled(true); get_ok()->set_disabled(_is_open_should_be_disabled()); for (int i = 0; i < favorites->get_item_count(); i++) { - if (favorites->get_item_metadata(i) == base_dir) { + if (favorites->get_item_metadata(i) == cdir) { favorites->select(i); favorite->set_pressed(true); if (i > 0) { @@ -854,27 +956,27 @@ void EditorFileDialog::set_mode(Mode p_mode) { case MODE_OPEN_FILE: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a File")); - makedir->hide(); + can_create_dir = false; break; case MODE_OPEN_FILES: get_ok()->set_text(TTR("Open")); set_title(TTR("Open File(s)")); - makedir->hide(); + can_create_dir = false; break; case MODE_OPEN_DIR: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a Directory")); - makedir->show(); + can_create_dir = true; break; case MODE_OPEN_ANY: get_ok()->set_text(TTR("Open")); set_title(TTR("Open a File or Directory")); - makedir->show(); + can_create_dir = true; break; case MODE_SAVE_FILE: get_ok()->set_text(TTR("Save")); set_title(TTR("Save a File")); - makedir->show(); + can_create_dir = true; break; } @@ -883,6 +985,12 @@ void EditorFileDialog::set_mode(Mode p_mode) { } else { item_list->set_select_mode(ItemList::SELECT_SINGLE); } + + if (can_create_dir) { + makedir->show(); + } else { + makedir->hide(); + } } EditorFileDialog::Mode EditorFileDialog::get_mode() const { @@ -954,6 +1062,28 @@ void EditorFileDialog::_make_dir() { makedirname->grab_focus(); } +void EditorFileDialog::_delete_items() { + + // Collect the selected folders and files to delete and check them in the deletion dependency dialog. + Vector<String> folders; + Vector<String> files; + for (int i = 0; i < item_list->get_item_count(); i++) { + if (!item_list->is_selected(i)) { + continue; + } + Dictionary item_meta = item_list->get_item_metadata(i); + if (item_meta["dir"]) { + folders.push_back(item_meta["path"]); + } else { + files.push_back(item_meta["path"]); + } + } + if (folders.size() + files.size() > 0) { + remove_dialog->set_size(Size2(1, 1)); + remove_dialog->show(folders, files); + } +} + void EditorFileDialog::_select_drive(int p_idx) { String d = drives->get_item_text(p_idx); @@ -1181,6 +1311,9 @@ void EditorFileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_item_selected"), &EditorFileDialog::_item_selected); ClassDB::bind_method(D_METHOD("_items_clear_selection"), &EditorFileDialog::_items_clear_selection); + ClassDB::bind_method(D_METHOD("_item_list_item_rmb_selected"), &EditorFileDialog::_item_list_item_rmb_selected); + ClassDB::bind_method(D_METHOD("_item_list_rmb_clicked"), &EditorFileDialog::_item_list_rmb_clicked); + ClassDB::bind_method(D_METHOD("_item_menu_id_pressed"), &EditorFileDialog::_item_menu_id_pressed); ClassDB::bind_method(D_METHOD("_item_db_selected"), &EditorFileDialog::_item_dc_selected); ClassDB::bind_method(D_METHOD("_dir_entered"), &EditorFileDialog::_dir_entered); ClassDB::bind_method(D_METHOD("_file_entered"), &EditorFileDialog::_file_entered); @@ -1232,6 +1365,15 @@ void EditorFileDialog::_bind_methods() { ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::POOL_STRING_ARRAY, "paths"))); ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir"))); + ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List"), "set_display_mode", "get_display_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR), "set_current_dir", "get_current_dir"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file", PROPERTY_HINT_FILE, "*"), "set_current_file", "get_current_file"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path"), "set_current_path", "get_current_path"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_overwrite_warning"), "set_disable_overwrite_warning", "is_overwrite_warning_disabled"); + BIND_ENUM_CONSTANT(MODE_OPEN_FILE); BIND_ENUM_CONSTANT(MODE_OPEN_FILES); BIND_ENUM_CONSTANT(MODE_OPEN_DIR); @@ -1317,6 +1459,7 @@ EditorFileDialog::EditorFileDialog() { ED_SHORTCUT("file_dialog/toggle_favorite", TTR("Toggle Favorite"), KEY_MASK_ALT | KEY_F); ED_SHORTCUT("file_dialog/toggle_mode", TTR("Toggle Mode"), KEY_MASK_ALT | KEY_V); ED_SHORTCUT("file_dialog/create_folder", TTR("Create Folder"), KEY_MASK_CMD | KEY_N); + ED_SHORTCUT("file_dialog/delete", TTR("Delete"), KEY_DELETE); ED_SHORTCUT("file_dialog/focus_path", TTR("Focus Path"), KEY_MASK_CMD | KEY_D); ED_SHORTCUT("file_dialog/move_favorite_up", TTR("Move Favorite Up"), KEY_MASK_CMD | KEY_UP); ED_SHORTCUT("file_dialog/move_favorite_down", TTR("Move Favorite Down"), KEY_MASK_CMD | KEY_DOWN); @@ -1423,10 +1566,21 @@ EditorFileDialog::EditorFileDialog() { list_vb->add_child(memnew(Label(TTR("Directories & Files:")))); preview_hb->add_child(list_vb); + // Item (files and folders) list with context menu + item_list = memnew(ItemList); item_list->set_v_size_flags(SIZE_EXPAND_FILL); + item_list->connect("item_rmb_selected", this, "_item_list_item_rmb_selected"); + item_list->connect("rmb_clicked", this, "_item_list_rmb_clicked"); + item_list->set_allow_rmb_select(true); list_vb->add_child(item_list); + item_menu = memnew(PopupMenu); + item_menu->connect("id_pressed", this, "_item_menu_id_pressed"); + add_child(item_menu); + + // Other stuff + preview_vb = memnew(VBoxContainer); preview_hb->add_child(preview_vb); CenterContainer *prev_cc = memnew(CenterContainer); @@ -1465,9 +1619,11 @@ EditorFileDialog::EditorFileDialog() { confirm_save = memnew(ConfirmationDialog); confirm_save->set_as_toplevel(true); add_child(confirm_save); - confirm_save->connect("confirmed", this, "_save_confirm_pressed"); + remove_dialog = memnew(DependencyRemoveDialog); + add_child(remove_dialog); + makedialog = memnew(ConfirmationDialog); makedialog->set_title(TTR("Create Folder")); VBoxContainer *makevb = memnew(VBoxContainer); diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 0599d222f3..f4a9a174e7 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -39,6 +39,9 @@ #include "scene/gui/split_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" + +class DependencyRemoveDialog; + /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -75,6 +78,14 @@ public: static RegisterFunc unregister_func; private: + enum ItemMenu { + ITEM_MENU_COPY_PATH, + ITEM_MENU_DELETE, + ITEM_MENU_REFRESH, + ITEM_MENU_NEW_FOLDER, + ITEM_MENU_SHOW_IN_EXPLORER + }; + ConfirmationDialog *makedialog; LineEdit *makedirname; @@ -83,6 +94,7 @@ private: //Button *action; VBoxContainer *vbox; Mode mode; + bool can_create_dir; LineEdit *dir; ToolButton *dir_prev; @@ -91,6 +103,7 @@ private: OptionButton *drives; ItemList *item_list; + PopupMenu *item_menu; TextureRect *preview; VBoxContainer *preview_vb; HSplitContainer *list_hb; @@ -100,6 +113,7 @@ private: OptionButton *filter; DirAccess *dir_access; ConfirmationDialog *confirm_save; + DependencyRemoveDialog *remove_dialog; ToolButton *mode_thumbnails; ToolButton *mode_list; @@ -146,6 +160,10 @@ private: void _items_clear_selection(); void _item_dc_selected(int p_item); + void _item_list_item_rmb_selected(int p_item, const Vector2 &p_pos); + void _item_list_rmb_clicked(const Vector2 &p_pos); + void _item_menu_id_pressed(int p_option); + void _select_drive(int p_idx); void _dir_entered(String p_dir); void _file_entered(const String &p_file); @@ -156,6 +174,8 @@ private: void _make_dir(); void _make_dir_confirm(); + void _delete_items(); + void _update_drives(); void _go_up(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 1cc518ff31..d462cce908 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1244,8 +1244,10 @@ void EditorFileSystem::update_file(const String &p_file) { if (!FileAccess::exists(p_file)) { //was removed _delete_internal_files(p_file); - memdelete(fs->files[cpos]); - fs->files.remove(cpos); + if (cpos != -1) { // Might've never been part of the editor file system (*.* files deleted in Open dialog). + memdelete(fs->files[cpos]); + fs->files.remove(cpos); + } call_deferred("emit_signal", "filesystem_changed"); //update later return; } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 5fc27c2e3c..8f427582ae 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -78,50 +78,40 @@ void EditorHelpSearch::_sbox_input(const Ref<InputEvent> &p_ie) { } } -void EditorHelpSearch::_update_search() { +class EditorHelpSearch::IncrementalSearch : public Reference { + String term; + TreeItem *root; - search_options->clear(); - search_options->set_hide_root(true); + EditorHelpSearch *search; + Tree *search_options; - /* - TreeItem *root = search_options->create_item(); - _parse_fs(EditorFileSystem::get_singleton()->get_filesystem()); -*/ + DocData *doc; + Ref<Texture> def_icon; - List<StringName> type_list; - ClassDB::get_class_list(&type_list); + int phase; + Map<String, DocData::ClassDoc>::Element *iterator; - DocData *doc = EditorHelp::get_doc_data(); - String term = search_box->get_text(); - if (term.length() < 2) - return; - - TreeItem *root = search_options->create_item(); - - Ref<Texture> def_icon = get_icon("Node", "EditorIcons"); - //classes first - for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { + void phase1(Map<String, DocData::ClassDoc>::Element *E) { if (E->key().findn(term) != -1) { TreeItem *item = search_options->create_item(root); item->set_metadata(0, "class_name:" + E->key()); item->set_text(0, E->key() + " (Class)"); - if (has_icon(E->key(), "EditorIcons")) - item->set_icon(0, get_icon(E->key(), "EditorIcons")); + if (search->has_icon(E->key(), "EditorIcons")) + item->set_icon(0, search->get_icon(E->key(), "EditorIcons")); else item->set_icon(0, def_icon); } } - //class methods, etc second - for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { + void phase2(Map<String, DocData::ClassDoc>::Element *E) { DocData::ClassDoc &c = E->get(); Ref<Texture> cicon; - if (has_icon(E->key(), "EditorIcons")) - cicon = get_icon(E->key(), "EditorIcons"); + if (search->has_icon(E->key(), "EditorIcons")) + cicon = search->get_icon(E->key(), "EditorIcons"); else cicon = def_icon; @@ -180,72 +170,80 @@ void EditorHelpSearch::_update_search() { } } - //same but descriptions + bool slice() { - for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) { + if (phase > 2) + return true; - DocData::ClassDoc &c = E->get(); + if (iterator) { - Ref<Texture> cicon; - if (has_icon(E->key(), "EditorIcons")) - cicon = get_icon(E->key(), "EditorIcons"); - else - cicon = def_icon; + switch (phase) { + + case 1: { + phase1(iterator); + } break; + case 2: { + phase2(iterator); + } break; + default: { + WARN_PRINT("illegal phase in IncrementalSearch"); + return true; + } + } - if (c.description.findn(term) != -1) { + iterator = iterator->next(); + } else { - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_desc:" + E->key()); - item->set_text(0, E->key() + " (Class Description)"); - item->set_icon(0, cicon); + phase += 1; + iterator = doc->class_list.front(); } - for (int i = 0; i < c.methods.size(); i++) { + return false; + } - if (c.methods[i].description.findn(term) != -1) { +public: + IncrementalSearch(EditorHelpSearch *p_search, Tree *p_search_options, const String &p_term) + : search(p_search), search_options(p_search_options) { - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_method_desc:" + E->key() + ":" + c.methods[i].name); - item->set_text(0, E->key() + "." + c.methods[i].name + " (Method Description)"); - item->set_icon(0, cicon); - } - } - - for (int i = 0; i < c.signals.size(); i++) { + def_icon = search->get_icon("Node", "EditorIcons"); + doc = EditorHelp::get_doc_data(); - if (c.signals[i].description.findn(term) != -1) { + term = p_term; - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_signal:" + E->key() + ":" + c.signals[i].name); - item->set_text(0, E->key() + "." + c.signals[i].name + " (Signal Description)"); - item->set_icon(0, cicon); - } - } + root = search_options->create_item(); + phase = 0; + iterator = 0; + } - for (int i = 0; i < c.constants.size(); i++) { + bool empty() const { - if (c.constants[i].description.findn(term) != -1) { + return root->get_children() == NULL; + } - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_constant:" + E->key() + ":" + c.constants[i].name); - item->set_text(0, E->key() + "." + c.constants[i].name + " (Constant Description)"); - item->set_icon(0, cicon); - } - } + bool work(uint64_t slot = 1000000 / 10) { - for (int i = 0; i < c.properties.size(); i++) { + const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot; - if (c.properties[i].description.findn(term) != -1) { + while (!slice()) { - TreeItem *item = search_options->create_item(root); - item->set_metadata(0, "class_property_desc:" + E->key() + ":" + c.properties[i].name); - item->set_text(0, E->key() + "." + c.properties[i].name + " (Property Description)"); - item->set_icon(0, cicon); - } + if (OS::get_singleton()->get_ticks_usec() > until) + return false; } + + return true; } +}; - get_ok()->set_disabled(root->get_children() == NULL); +void EditorHelpSearch::_update_search() { + search_options->clear(); + search_options->set_hide_root(true); + + String term = search_box->get_text(); + if (term.length() < 2) + return; + + search = Ref<IncrementalSearch>(memnew(IncrementalSearch(this, search_options, term))); + set_process(true); } void EditorHelpSearch::_confirmed() { @@ -281,6 +279,20 @@ void EditorHelpSearch::_notification(int p_what) { //_update_icons search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + } else if (p_what == NOTIFICATION_PROCESS) { + + if (search.is_valid()) { + + if (search->work()) { + + get_ok()->set_disabled(search->empty()); + search = Ref<IncrementalSearch>(); + set_process(false); + } + } else { + + set_process(false); + } } } diff --git a/editor/editor_help.h b/editor/editor_help.h index 92c0e2f4d1..a224c7f8ee 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -53,6 +53,9 @@ class EditorHelpSearch : public ConfirmationDialog { Tree *search_options; String base_type; + class IncrementalSearch; + Ref<IncrementalSearch> search; + void _update_search(); void _sbox_input(const Ref<InputEvent> &p_ie); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d6c8d65193..0252358a27 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -269,6 +269,7 @@ void EditorNode::_notification(int p_what) { Engine::get_singleton()->set_editor_hint(true); + get_tree()->get_root()->set_usage(Viewport::USAGE_2D_NO_SAMPLING); //reduce memory usage get_tree()->get_root()->set_disable_3d(true); get_tree()->get_root()->set_as_audio_listener(false); get_tree()->get_root()->set_as_audio_listener_2d(false); @@ -337,7 +338,13 @@ void EditorNode::_notification(int p_what) { //_update_icons for (int i = 0; i < singleton->main_editor_buttons.size(); i++) { - main_editor_buttons[i]->set_icon(gui_base->get_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons")); + Ref<Texture> icon = singleton->main_editor_buttons[i]->get_icon(); + + if (icon.is_valid()) { + main_editor_buttons[i]->set_icon(icon); + } else if (singleton->gui_base->has_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons")) { + main_editor_buttons[i]->set_icon(gui_base->get_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons")); + } } play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons")); play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons")); @@ -1394,11 +1401,13 @@ void EditorNode::_property_editor_back() { } void EditorNode::_menu_collapseall() { - property_editor->collapse_all_parent_nodes(); + + property_editor->collapse_all_folding(); } void EditorNode::_menu_expandall() { - property_editor->expand_all_parent_nodes(); + + property_editor->expand_all_folding(); } void EditorNode::_save_default_environment() { @@ -2670,7 +2679,14 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor) { tb->set_toggle_mode(true); tb->connect("pressed", singleton, "_editor_select", varray(singleton->main_editor_buttons.size())); tb->set_text(p_editor->get_name()); - tb->set_icon(singleton->gui_base->get_icon(p_editor->get_name(), "EditorIcons")); + Ref<Texture> icon = p_editor->get_icon(); + + if (icon.is_valid()) { + tb->set_icon(icon); + } else if (singleton->gui_base->has_icon(p_editor->get_name(), "EditorIcons")) { + tb->set_icon(singleton->gui_base->get_icon(p_editor->get_name(), "EditorIcons")); + } + tb->set_name(p_editor->get_name()); singleton->main_editor_buttons.push_back(tb); singleton->main_editor_button_vb->add_child(tb); @@ -3348,6 +3364,8 @@ void EditorNode::register_editor_types() { ClassDB::register_virtual_class<EditorInterface>(); ClassDB::register_class<EditorExportPlugin>(); ClassDB::register_class<EditorResourceConversionPlugin>(); + ClassDB::register_class<EditorSceneImporter>(); + // FIXME: Is this stuff obsolete, or should it be ported to new APIs? ClassDB::register_class<EditorScenePostImport>(); @@ -5019,6 +5037,7 @@ EditorNode::EditorNode() { scene_root_parent->set_v_size_flags(Control::SIZE_EXPAND_FILL); scene_root = memnew(Viewport); + scene_root->set_usage(Viewport::USAGE_2D); scene_root->set_disable_3d(true); VisualServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport_rid(), true); @@ -5444,7 +5463,7 @@ EditorNode::EditorNode() { property_editor->set_use_doc_hints(true); property_editor->set_hide_script(false); property_editor->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true))); - property_editor->set_use_folding(bool(EDITOR_DEF("interface/editor/expand_all_properties", false)) == false); + property_editor->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false))); property_editor->hide_top_label(); property_editor->register_text_enter(search_box); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index c1fbcde6ac..5c4c2b694f 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -466,6 +466,14 @@ String EditorPlugin::get_name() const { return String(); } +const Ref<Texture> EditorPlugin::get_icon() const { + + if (get_script_instance() && get_script_instance()->has_method("get_plugin_icon")) { + return get_script_instance()->call("get_plugin_icon"); + } + + return Ref<Texture>(); +} bool EditorPlugin::has_main_screen() const { if (get_script_instance() && get_script_instance()->has_method("has_main_screen")) { @@ -557,12 +565,12 @@ void EditorPlugin::save_global_state() {} void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer) { ResourceFormatImporter::get_singleton()->add_importer(p_importer); - EditorFileSystem::get_singleton()->scan(); + EditorFileSystem::get_singleton()->call_deferred("scan"); } void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) { ResourceFormatImporter::get_singleton()->remove_importer(p_importer); - EditorFileSystem::get_singleton()->scan(); + EditorFileSystem::get_singleton()->call_deferred("scan"); } void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) { @@ -573,6 +581,14 @@ void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin> &p_exporte EditorExport::get_singleton()->remove_export_plugin(p_exporter); } +void EditorPlugin::add_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) { + ResourceImporterScene::get_singleton()->add_importer(p_importer); +} + +void EditorPlugin::remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) { + ResourceImporterScene::get_singleton()->remove_importer(p_importer); +} + void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { if (get_script_instance() && get_script_instance()->has_method("set_window_layout")) { @@ -628,6 +644,8 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout); ClassDB::bind_method(D_METHOD("add_import_plugin", "importer"), &EditorPlugin::add_import_plugin); ClassDB::bind_method(D_METHOD("remove_import_plugin", "importer"), &EditorPlugin::remove_import_plugin); + ClassDB::bind_method(D_METHOD("add_scene_import_plugin", "scene_importer"), &EditorPlugin::add_scene_import_plugin); + ClassDB::bind_method(D_METHOD("remove_scene_import_plugin", "scene_importer"), &EditorPlugin::remove_scene_import_plugin); ClassDB::bind_method(D_METHOD("add_export_plugin", "exporter"), &EditorPlugin::add_export_plugin); ClassDB::bind_method(D_METHOD("remove_export_plugin", "exporter"), &EditorPlugin::remove_export_plugin); ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled); @@ -644,6 +662,7 @@ void EditorPlugin::_bind_methods() { gizmo.return_val.hint_string = "EditorSpatialGizmo"; ClassDB::add_virtual_method(get_class_static(), gizmo); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name")); + ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::OBJECT, "get_plugin_icon")); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "has_main_screen")); ClassDB::add_virtual_method(get_class_static(), MethodInfo("make_visible", PropertyInfo(Variant::BOOL, "visible"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo("edit", PropertyInfo(Variant::OBJECT, "object"))); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 11f4378667..89a6d3d250 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -35,6 +35,7 @@ #include "scene/gui/tool_button.h" #include "scene/main/node.h" #include "scene/resources/texture.h" +#include "editor/import/resource_importer_scene.h" #include "undo_redo.h" /** @@ -165,6 +166,7 @@ public: virtual void forward_force_draw_over_viewport(Control *p_overlay); virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event); virtual String get_name() const; + virtual const Ref<Texture> get_icon() const; virtual bool has_main_screen() const; virtual void make_visible(bool p_visible); virtual void selected_notify() {} //notify that it was raised by the user, not the editor @@ -199,6 +201,9 @@ public: void add_export_plugin(const Ref<EditorExportPlugin> &p_exporter); void remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter); + void add_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer); + void remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer); + EditorPlugin(); virtual ~EditorPlugin(); }; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 2f73e459ed..d199b27b83 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -348,7 +348,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/files/autosave_interval_secs", 0); _initial_set("text_editor/cursor/block_caret", false); - _initial_set("text_editor/cursor/caret_blink", false); + _initial_set("text_editor/cursor/caret_blink", true); _initial_set("text_editor/cursor/caret_blink_speed", 0.65); hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.1"); @@ -543,6 +543,7 @@ void EditorSettings::_load_default_text_editor_theme() { _initial_set("text_editor/highlighting/line_length_guideline_color", Color(0.3, 0.5, 0.8, 0.1)); _initial_set("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4)); _initial_set("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2)); + _initial_set("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8)); _initial_set("text_editor/highlighting/word_highlighted_color", Color(0.8, 0.9, 0.9, 0.15)); _initial_set("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1)); _initial_set("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1)); @@ -577,6 +578,7 @@ bool EditorSettings::_save_text_editor_theme(String p_file) { cf->set_value(theme_section, "line_length_guideline_color", ((Color)get("text_editor/highlighting/line_length_guideline_color")).to_html()); cf->set_value(theme_section, "mark_color", ((Color)get("text_editor/highlighting/mark_color")).to_html()); cf->set_value(theme_section, "breakpoint_color", ((Color)get("text_editor/highlighting/breakpoint_color")).to_html()); + cf->set_value(theme_section, "code_folding_color", ((Color)get("text_editor/highlighting/code_folding_color")).to_html()); cf->set_value(theme_section, "word_highlighted_color", ((Color)get("text_editor/highlighting/word_highlighted_color")).to_html()); cf->set_value(theme_section, "search_result_color", ((Color)get("text_editor/highlighting/search_result_color")).to_html()); cf->set_value(theme_section, "search_result_border_color", ((Color)get("text_editor/highlighting/search_result_border_color")).to_html()); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index ae29b7420e..4661fcf668 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -793,6 +793,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // TextEdit theme->set_stylebox("normal", "TextEdit", style_widget); theme->set_stylebox("focus", "TextEdit", style_widget_hover); + theme->set_stylebox("read_only", "TextEdit", style_widget_disabled); theme->set_constant("side_margin", "TabContainer", 0); theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons")); theme->set_color("font_color", "TextEdit", font_color); @@ -1038,6 +1039,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color member_variable_color = mono_color; const Color mark_color = Color(error_color.r, error_color.g, error_color.b, 0.3); const Color breakpoint_color = error_color; + const Color code_folding_color = alpha4; const Color search_result_color = alpha1; const Color search_result_border_color = alpha4; @@ -1068,6 +1070,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("text_editor/theme/member_variable_color", "Editor", member_variable_color); theme->set_color("text_editor/theme/mark_color", "Editor", mark_color); theme->set_color("text_editor/theme/breakpoint_color", "Editor", breakpoint_color); + theme->set_color("text_editor/theme/code_folding_color", "Editor", code_folding_color); theme->set_color("text_editor/theme/search_result_color", "Editor", search_result_color); theme->set_color("text_editor/theme/search_result_border_color", "Editor", search_result_border_color); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 9fe3e2ad25..9ece36ea80 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -806,6 +806,39 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_ memdelete(da); } +void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const { + //Ensure folder paths end with "/" + String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/"); + String new_path = (p_item.is_file || p_new_path.ends_with("/")) ? p_new_path : (p_new_path + "/"); + + if (new_path == old_path) { + return; + } else if (old_path == "res://") { + EditorNode::get_singleton()->add_io_error(TTR("Cannot move/rename resources root.")); + return; + } else if (!p_item.is_file && new_path.begins_with(old_path)) { + //This check doesn't erroneously catch renaming to a longer name as folder paths always end with "/" + EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.\n") + old_path + "\n"); + return; + } + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + print_line("Duplicating " + old_path + " -> " + new_path); + Error err = da->copy(old_path, new_path); + if (err == OK) { + //Move/Rename any corresponding import settings too + if (p_item.is_file && FileAccess::exists(old_path + ".import")) { + err = da->copy(old_path + ".import", new_path + ".import"); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:\n") + old_path + ".import\n"); + } + } + } else { + EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:\n") + old_path + "\n"); + } + memdelete(da); +} + void FileSystemDock::_update_dependencies_after_move(const Map<String, String> &p_renames) const { //The following code assumes that the following holds: // 1) EditorFileSystem contains the old paths/folder structure from before the rename/move. @@ -888,6 +921,39 @@ void FileSystemDock::_rename_operation_confirm() { _rescan(); } +void FileSystemDock::_duplicate_operation_confirm() { + + String new_name = duplicate_dialog_text->get_text().strip_edges(); + if (new_name.length() == 0) { + EditorNode::get_singleton()->show_warning(TTR("No name provided.")); + return; + } else if (new_name.find("/") != -1 || new_name.find("\\") != -1 || new_name.find(":") != -1) { + EditorNode::get_singleton()->show_warning(TTR("Name contains invalid characters.")); + return; + } + + String old_path = to_duplicate.path.ends_with("/") ? to_duplicate.path.substr(0, to_duplicate.path.length() - 1) : to_rename.path; + String new_path = old_path.get_base_dir().plus_file(new_name); + if (old_path == new_path) { + return; + } + + //Present a more user friendly warning for name conflict + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da->file_exists(new_path) || da->dir_exists(new_path)) { + EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists.")); + memdelete(da); + return; + } + memdelete(da); + + _try_duplicate_item(to_duplicate, new_name); + + //Rescan everything + print_line("call rescan!"); + _rescan(); +} + void FileSystemDock::_move_operation_confirm(const String &p_to_path) { Map<String, String> renames; @@ -909,10 +975,11 @@ void FileSystemDock::_file_option(int p_option) { OS::get_singleton()->shell_open(String("file://") + dir); } break; case FILE_OPEN: { - int idx = files->get_current(); - if (idx < 0 || idx >= files->get_item_count()) - break; - _select_file(idx); + for (int i = 0; i < files->get_item_count(); i++) { + if (files->is_selected(i)) { + _select_file(i); + } + } } break; case FILE_INSTANCE: { @@ -1002,6 +1069,27 @@ void FileSystemDock::_file_option(int p_option) { //2) warn } } break; + case FILE_DUPLICATE: { + int idx = files->get_current(); + if (idx < 0 || idx >= files->get_item_count()) + break; + + to_duplicate.path = files->get_item_metadata(idx); + to_duplicate.is_file = !to_duplicate.path.ends_with("/"); + if (to_duplicate.is_file) { + String name = to_duplicate.path.get_file(); + duplicate_dialog->set_title(TTR("Duplicating file:") + " " + name); + duplicate_dialog_text->set_text(name); + duplicate_dialog_text->select(0, name.find_last(".")); + } else { + String name = to_duplicate.path.substr(0, to_duplicate.path.length() - 1).get_file(); + duplicate_dialog->set_title(TTR("Duplicating folder:") + " " + name); + duplicate_dialog_text->set_text(name); + duplicate_dialog_text->select(0, name.length()); + } + duplicate_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE); + duplicate_dialog_text->grab_focus(); + } break; case FILE_INFO: { } break; @@ -1429,18 +1517,25 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { file_options->clear(); file_options->set_size(Size2(1, 1)); - if (all_files && filenames.size() > 0) { - file_options->add_item(TTR("Open"), FILE_OPEN); - if (all_files_scenes) { + if (all_files) { + + if (all_files_scenes && filenames.size() >= 1) { + file_options->add_item(TTR("Open Scene(s)"), FILE_OPEN); file_options->add_item(TTR("Instance"), FILE_INSTANCE); + file_options->add_separator(); + } + + if (!all_files_scenes && filenames.size() == 1) { + file_options->add_item(TTR("Open"), FILE_OPEN); + file_options->add_separator(); } - file_options->add_separator(); if (filenames.size() == 1) { file_options->add_item(TTR("Edit Dependencies.."), FILE_DEPENDENCIES); file_options->add_item(TTR("View Owners.."), FILE_OWNERS); file_options->add_separator(); } + } else if (all_folders && foldernames.size() > 0) { file_options->add_item(TTR("Open"), FILE_OPEN); file_options->add_separator(); @@ -1451,6 +1546,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { if (num_items == 1) { file_options->add_item(TTR("Copy Path"), FILE_COPY_PATH); file_options->add_item(TTR("Rename.."), FILE_RENAME); + file_options->add_item(TTR("Duplicate.."), FILE_DUPLICATE); } file_options->add_item(TTR("Move To.."), FILE_MOVE); file_options->add_item(TTR("Delete"), FILE_REMOVE); @@ -1562,6 +1658,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm); ClassDB::bind_method(D_METHOD("_move_operation_confirm"), &FileSystemDock::_move_operation_confirm); ClassDB::bind_method(D_METHOD("_rename_operation_confirm"), &FileSystemDock::_rename_operation_confirm); + ClassDB::bind_method(D_METHOD("_duplicate_operation_confirm"), &FileSystemDock::_duplicate_operation_confirm); ClassDB::bind_method(D_METHOD("_search_changed"), &FileSystemDock::_search_changed); @@ -1735,6 +1832,17 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { rename_dialog->register_text_enter(rename_dialog_text); rename_dialog->connect("confirmed", this, "_rename_operation_confirm"); + duplicate_dialog = memnew(ConfirmationDialog); + VBoxContainer *duplicate_dialog_vb = memnew(VBoxContainer); + duplicate_dialog->add_child(duplicate_dialog_vb); + + duplicate_dialog_text = memnew(LineEdit); + duplicate_dialog_vb->add_margin_child(TTR("Name:"), duplicate_dialog_text); + duplicate_dialog->get_ok()->set_text(TTR("Duplicate")); + add_child(duplicate_dialog); + duplicate_dialog->register_text_enter(duplicate_dialog_text); + duplicate_dialog->connect("confirmed", this, "_duplicate_operation_confirm"); + make_dir_dialog = memnew(ConfirmationDialog); make_dir_dialog->set_title(TTR("Create Folder")); VBoxContainer *make_folder_dialog_vb = memnew(VBoxContainer); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index f1fd342052..bc8d835ba1 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -70,6 +70,7 @@ private: FILE_MOVE, FILE_RENAME, FILE_REMOVE, + FILE_DUPLICATE, FILE_REIMPORT, FILE_INFO, FILE_NEW_FOLDER, @@ -120,6 +121,8 @@ private: EditorDirDialog *move_dialog; ConfirmationDialog *rename_dialog; LineEdit *rename_dialog_text; + ConfirmationDialog *duplicate_dialog; + LineEdit *duplicate_dialog_text; ConfirmationDialog *make_dir_dialog; LineEdit *make_dir_dialog_text; @@ -128,12 +131,15 @@ private: String path; bool is_file; - FileOrFolder() - : path(""), is_file(false) {} - FileOrFolder(const String &p_path, bool p_is_file) - : path(p_path), is_file(p_is_file) {} + FileOrFolder() : + path(""), + is_file(false) {} + FileOrFolder(const String &p_path, bool p_is_file) : + path(p_path), + is_file(p_is_file) {} }; FileOrFolder to_rename; + FileOrFolder to_duplicate; Vector<FileOrFolder> to_move; Vector<String> history; @@ -170,10 +176,12 @@ private: void _get_all_files_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files) const; void _find_remaps(EditorFileSystemDirectory *efsd, const Map<String, String> &renames, Vector<String> &to_remaps) const; void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, Map<String, String> &p_renames) const; + void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const; void _update_dependencies_after_move(const Map<String, String> &p_renames) const; void _make_dir_confirm(); void _rename_operation_confirm(); + void _duplicate_operation_confirm(); void _move_operation_confirm(const String &p_to_path); void _file_option(int p_option); diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 3c73411dee..c38391c71b 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -1913,8 +1913,6 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones /*************************************** SCENE ***********************************/ /*********************************************************************************/ -#define DEBUG_ANIMATION - uint32_t EditorSceneImporterCollada::get_import_flags() const { return IMPORT_SCENE | IMPORT_ANIMATION; @@ -1981,7 +1979,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_ return state.scene; } -Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path, uint32_t p_flags) { +Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps) { ColladaImport state; diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h index 865a72739f..986b5b766f 100644 --- a/editor/import/editor_import_collada.h +++ b/editor/import/editor_import_collada.h @@ -40,7 +40,7 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps); EditorSceneImporterCollada(); }; diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index f704d97373..e801f3e7c3 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -2106,7 +2106,7 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_fla return scene; } -Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path, uint32_t p_flags) { +Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { return Ref<Animation>(); } diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index d9479fae6f..0c8000427e 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -296,7 +296,7 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps); EditorSceneImporterGLTF(); }; diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 14bda9bb4e..0297a6c24e 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -426,7 +426,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in return scene; } -Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags) { +Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { return Ref<Animation>(); } diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h index 7eeceeabbe..09dc8ac8a1 100644 --- a/editor/import/resource_importer_obj.h +++ b/editor/import/resource_importer_obj.h @@ -40,7 +40,7 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL); - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps); EditorOBJImporter(); }; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 95445693b4..08d2897250 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -47,6 +47,85 @@ #include "scene/resources/ray_shape.h" #include "scene/resources/sphere_shape.h" +uint32_t EditorSceneImporter::get_import_flags() const { + + if (get_script_instance()) { + return get_script_instance()->call("_get_import_flags"); + } + + ERR_FAIL_V(0); +} +void EditorSceneImporter::get_extensions(List<String> *r_extensions) const { + + if (get_script_instance()) { + Array arr = get_script_instance()->call("_get_extensions"); + for (int i = 0; i < arr.size(); i++) { + r_extensions->push_back(arr[i]); + } + return; + } + + ERR_FAIL(); +} +Node *EditorSceneImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { + + if (get_script_instance()) { + return get_script_instance()->call("_import_scene", p_path, p_flags, p_bake_fps); + } + + ERR_FAIL_V(NULL); +} + +Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) { + + if (get_script_instance()) { + return get_script_instance()->call("_import_animation", p_path, p_flags); + } + + ERR_FAIL_V(NULL); +} + +//for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf), +//and you want to load the resulting file + +Node *EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { + + return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps); +} + +Ref<Animation> EditorSceneImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) { + + return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps); +} + +void EditorSceneImporter::_bind_methods() { + + ClassDB::bind_method(D_METHOD("import_scene_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_scene_from_other_importer); + ClassDB::bind_method(D_METHOD("import_animation_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_animation_from_other_importer); + + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_import_flags")); + BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_extensions")); + + MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); + mi.return_val.class_name = "Node"; + BIND_VMETHOD(mi); + mi = MethodInfo(Variant::OBJECT, "_import_animation", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps")); + mi.return_val.class_name = "Animation"; + BIND_VMETHOD(mi); + + BIND_CONSTANT(IMPORT_SCENE); + BIND_CONSTANT(IMPORT_ANIMATION); + BIND_CONSTANT(IMPORT_ANIMATION_DETECT_LOOP); + BIND_CONSTANT(IMPORT_ANIMATION_OPTIMIZE); + BIND_CONSTANT(IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS); + BIND_CONSTANT(IMPORT_ANIMATION_KEEP_VALUE_TRACKS); + BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS); + BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES); + BIND_CONSTANT(IMPORT_MATERIALS_IN_INSTANCES); + BIND_CONSTANT(IMPORT_USE_COMPRESSION); +} + +///////////////////////////////// void EditorScenePostImport::_bind_methods() { BIND_VMETHOD(MethodInfo("post_import", PropertyInfo(Variant::OBJECT, "scene"))); @@ -95,6 +174,9 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const if (p_option != "animation/import" && !bool(p_options["animation/import"])) return false; + if (p_option == "animation/keep_custom_tracks" && int(p_options["animation/storage"]) == 0) + return false; + if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"])) return false; @@ -110,6 +192,10 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const return false; } + if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) { + return false; + } + return true; } @@ -870,7 +956,37 @@ static String _make_extname(const String &p_str) { return ext_name; } -void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) { +void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) { + + List<PropertyInfo> pi; + p_node->get_property_list(&pi); + + MeshInstance *mi = Object::cast_to<MeshInstance>(p_node); + + if (mi) { + + Ref<ArrayMesh> mesh = mi->get_mesh(); + + if (mesh.is_valid() && !meshes.has(mesh)) { + Spatial *s = mi; + while (s->get_parent_spatial()) { + s = s->get_parent_spatial(); + } + + if (s == mi) { + meshes[mesh] = s->get_transform(); + } else { + meshes[mesh] = s->get_transform() * mi->get_relative_transform(s); + } + } + } + for (int i = 0; i < p_node->get_child_count(); i++) { + + _find_meshes(p_node->get_child(i), meshes); + } +} + +void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) { List<PropertyInfo> pi; @@ -889,7 +1005,26 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String if (!p_animations.has(anim)) { + //mark what comes from the file first, this helps eventually keep user data + for (int i = 0; i < anim->get_track_count(); i++) { + anim->track_set_imported(i, true); + } + String ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".anim"); + + if (FileAccess::exists(ext_name) && p_keep_animations) { + //try to keep custom animation tracks + Ref<Animation> old_anim = ResourceLoader::load(ext_name, "Animation", true); + if (old_anim.is_valid()) { + //meergeee + for (int i = 0; i < old_anim->get_track_count(); i++) { + if (!old_anim->track_is_imported(i)) { + old_anim->copy_track(i, anim); + } + } + } + } + ResourceSaver::save(ext_name, anim, ResourceSaver::FLAG_CHANGE_PATH); p_animations[anim] = anim; } @@ -997,7 +1132,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String for (int i = 0; i < p_node->get_child_count(); i++) { - _make_external_resources(p_node->get_child(i), p_base_path, p_make_animations, p_make_materials, p_keep_materials, p_make_meshes, p_animations, p_materials, p_meshes); + _make_external_resources(p_node->get_child(i), p_base_path, p_make_animations, p_keep_animations, p_make_materials, p_keep_materials, p_make_meshes, p_animations, p_materials, p_meshes); } } @@ -1030,12 +1165,14 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? 1 : 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.05)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), animations_out ? true : false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out ? true : false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_linear_error"), 0.05)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_angular_error"), 0.01)); @@ -1062,6 +1199,68 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_ } } +Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { + + Ref<EditorSceneImporter> importer; + String ext = p_path.get_extension().to_lower(); + + for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) { + + if (E->get().ptr() == p_exception) + continue; + List<String> extensions; + E->get()->get_extensions(&extensions); + + for (List<String>::Element *F = extensions.front(); F; F = F->next()) { + + if (F->get().to_lower() == ext) { + + importer = E->get(); + break; + } + } + + if (importer.is_valid()) + break; + } + + ERR_FAIL_COND_V(!importer.is_valid(), NULL); + + List<String> missing; + Error err; + return importer->import_scene(p_path, p_flags, p_bake_fps, &missing, &err); +} + +Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) { + + Ref<EditorSceneImporter> importer; + String ext = p_path.get_extension().to_lower(); + + for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) { + + if (E->get().ptr() == p_exception) + continue; + List<String> extensions; + E->get()->get_extensions(&extensions); + + for (List<String>::Element *F = extensions.front(); F; F = F->next()) { + + if (F->get().to_lower() == ext) { + + importer = E->get(); + break; + } + } + + if (importer.is_valid()) + break; + } + + ERR_FAIL_COND_V(!importer.is_valid(), NULL); + + return importer->import_animation(p_path, p_flags, p_bake_fps); +} + Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { String src_path = p_source_file; @@ -1176,6 +1375,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } bool external_animations = int(p_options["animation/storage"]) == 1; + bool keep_custom_tracks = p_options["animation/keep_custom_tracks"]; bool external_materials = p_options["materials/storage"]; bool external_meshes = p_options["meshes/storage"]; bool external_scenes = int(p_options["nodes/storage"]) == 1; @@ -1195,6 +1395,37 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } } + if (light_bake_mode == 2 /* || generate LOD */) { + + Map<Ref<ArrayMesh>, Transform> meshes; + _find_meshes(scene, meshes); + + if (light_bake_mode == 2) { + + float texel_size = p_options["meshes/lightmap_texel_size"]; + texel_size = MAX(0.001, texel_size); + + EditorProgress progress("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size()); + int step = 0; + for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) { + + Ref<ArrayMesh> mesh = E->key(); + String name = mesh->get_name(); + if (name == "") { //should not happen but.. + name = "Mesh " + itos(step); + } + + progress.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step); + + Error err = mesh->lightmap_unwrap(E->get(), texel_size); + if (err != OK) { + EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry."); + } + step++; + } + } + } + if (external_animations || external_materials || external_meshes) { Map<Ref<Animation>, Ref<Animation> > anim_map; Map<Ref<Material>, Ref<Material> > mat_map; @@ -1202,7 +1433,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p bool keep_materials = bool(p_options["materials/keep_on_reimport"]); - _make_external_resources(scene, base_path, external_animations, external_materials, keep_materials, external_meshes, anim_map, mat_map, mesh_map); + _make_external_resources(scene, base_path, external_animations, keep_custom_tracks, external_materials, keep_materials, external_meshes, anim_map, mat_map, mesh_map); } progress.step(TTR("Running Custom Script.."), 2); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 92777fafb6..933585a48c 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -41,6 +41,12 @@ class EditorSceneImporter : public Reference { GDCLASS(EditorSceneImporter, Reference); +protected: + static void _bind_methods(); + + Node *import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); + Ref<Animation> import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps); + public: enum ImportFlags { IMPORT_SCENE = 1, @@ -56,10 +62,10 @@ public: }; - virtual uint32_t get_import_flags() const = 0; - virtual void get_extensions(List<String> *r_extensions) const = 0; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL) = 0; - virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags) = 0; + virtual uint32_t get_import_flags() const; + virtual void get_extensions(List<String> *r_extensions) const; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL); + virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps); EditorSceneImporter() {} }; @@ -114,6 +120,7 @@ public: const Set<Ref<EditorSceneImporter> > &get_importers() const { return importers; } void add_importer(Ref<EditorSceneImporter> p_importer) { importers.insert(p_importer); } + void remove_importer(Ref<EditorSceneImporter> p_importer) { importers.erase(p_importer); } virtual String get_importer_name() const; virtual String get_visible_name() const; @@ -128,7 +135,9 @@ public: virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; virtual int get_import_order() const { return 100; } //after everything - void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes); + void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes); + + void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes); Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map, LightBakeMode p_light_bake_mode); @@ -139,6 +148,9 @@ public: virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); + Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps); + ResourceImporterScene(); }; diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index cabdfa761d..ff72a5a25e 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -32,18 +32,21 @@ #include "canvas_item_editor_plugin.h" #include "core/os/keyboard.h" -AbstractPolygon2DEditor::Vertex::Vertex() - : polygon(-1), vertex(-1) { +AbstractPolygon2DEditor::Vertex::Vertex() : + polygon(-1), + vertex(-1) { // invalid vertex } -AbstractPolygon2DEditor::Vertex::Vertex(int p_vertex) - : polygon(-1), vertex(p_vertex) { +AbstractPolygon2DEditor::Vertex::Vertex(int p_vertex) : + polygon(-1), + vertex(p_vertex) { // vertex p_vertex of current wip polygon } -AbstractPolygon2DEditor::Vertex::Vertex(int p_polygon, int p_vertex) - : polygon(p_polygon), vertex(p_vertex) { +AbstractPolygon2DEditor::Vertex::Vertex(int p_polygon, int p_vertex) : + polygon(p_polygon), + vertex(p_vertex) { // vertex p_vertex of polygon p_polygon } @@ -66,12 +69,14 @@ AbstractPolygon2DEditor::PosVertex::PosVertex() { // invalid vertex } -AbstractPolygon2DEditor::PosVertex::PosVertex(const Vertex &p_vertex, const Vector2 &p_pos) - : Vertex(p_vertex.polygon, p_vertex.vertex), pos(p_pos) { +AbstractPolygon2DEditor::PosVertex::PosVertex(const Vertex &p_vertex, const Vector2 &p_pos) : + Vertex(p_vertex.polygon, p_vertex.vertex), + pos(p_pos) { } -AbstractPolygon2DEditor::PosVertex::PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos) - : Vertex(p_polygon, p_vertex), pos(p_pos) { +AbstractPolygon2DEditor::PosVertex::PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos) : + Vertex(p_polygon, p_vertex), + pos(p_pos) { } bool AbstractPolygon2DEditor::_is_empty() const { @@ -167,7 +172,7 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) { } break; case MODE_EDIT: { - wip_active = false; + _wip_close(); mode = MODE_EDIT; button_create->set_pressed(false); button_edit->set_pressed(true); @@ -175,7 +180,7 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) { } break; case MODE_DELETE: { - wip_active = false; + _wip_close(); mode = MODE_DELETE; button_create->set_pressed(false); button_edit->set_pressed(false); @@ -224,6 +229,9 @@ void AbstractPolygon2DEditor::_wip_changed() { } void AbstractPolygon2DEditor::_wip_close() { + if (!wip_active) + return; + if (_is_line()) { _set_polygon(0, wip); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index a7733cd2d9..e63bc3ad9f 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -69,8 +69,8 @@ class SnapDialog : public ConfirmationDialog { SpinBox *rotation_step; public: - SnapDialog() - : ConfirmationDialog() { + SnapDialog() : + ConfirmationDialog() { const int SPIN_BOX_GRID_RANGE = 256; const int SPIN_BOX_ROTATION_RANGE = 360; Label *label; @@ -4489,15 +4489,24 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(ResourceCache::get(path))); Size2 texture_size = texture->get_size(); - editor_data->get_undo_redo().add_do_method(parent, "add_child", child); - editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(child); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); + if (parent) { + editor_data->get_undo_redo().add_do_method(parent, "add_child", child); + editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); + editor_data->get_undo_redo().add_do_reference(child); + editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); + } else { // if we haven't parent, lets try to make a child as a parent. + editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child); + editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); + editor_data->get_undo_redo().add_do_reference(child); + editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL); + } - String new_name = parent->validate_child_name(child); - ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); - editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); - editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + if (parent) { + String new_name = parent->validate_child_name(child); + ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger(); + editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name); + editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); + } // handle with different property for texture String property = "texture"; @@ -4530,8 +4539,8 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & } // locate at preview position - Point2 pos; - if (parent->has_method("get_global_position")) { + Point2 pos = Point2(0, 0); + if (parent && parent->has_method("get_global_position")) { pos = parent->call("get_global_position"); } Transform2D trans = canvas->get_canvas_transform(); @@ -4692,6 +4701,18 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian return false; } +void CanvasItemEditorViewport::_show_resource_type_selector() { + List<BaseButton *> btn_list; + button_group->get_buttons(&btn_list); + + for (int i = 0; i < btn_list.size(); i++) { + CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]); + check->set_pressed(check->get_text() == default_type); + } + selector->set_title(vformat(TTR("Add %s"), default_type)); + selector->popup_centered_minsize(); +} + void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) { bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT); bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT); @@ -4708,10 +4729,8 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p if (root_node) { list.push_back(root_node); } else { - accept->get_ok()->set_text(TTR("OK :(")); - accept->set_text(TTR("No parent to instance a child at.")); - accept->popup_centered_minsize(); - _remove_preview(); + drop_pos = p_point; + _show_resource_type_selector(); return; } } @@ -4730,15 +4749,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p drop_pos = p_point; if (is_alt) { - List<BaseButton *> btn_list; - button_group->get_buttons(&btn_list); - - for (int i = 0; i < btn_list.size(); i++) { - CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]); - check->set_pressed(check->get_text() == default_type); - } - selector->set_title(vformat(TTR("Add %s"), default_type)); - selector->popup_centered_minsize(); + _show_resource_type_selector(); } else { _perform_drop_data(); } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 457833e1a7..4be09a16e9 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -578,6 +578,7 @@ class CanvasItemEditorViewport : public Control { void _create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point); bool _create_instance(Node *parent, String &path, const Point2 &p_point); void _perform_drop_data(); + void _show_resource_type_selector(); static void _bind_methods(); diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp index 00e6d617a1..6ac80caf94 100644 --- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp @@ -39,10 +39,10 @@ void CollisionPolygon2DEditor::_set_node(Node *p_polygon) { node = Object::cast_to<CollisionPolygon2D>(p_polygon); } -CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) - : AbstractPolygon2DEditor(p_editor) { +CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) : + AbstractPolygon2DEditor(p_editor) { } -CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) - : AbstractPolygon2DEditorPlugin(p_node, memnew(CollisionPolygon2DEditor(p_node)), "CollisionPolygon2D") { +CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) : + AbstractPolygon2DEditorPlugin(p_node, memnew(CollisionPolygon2DEditor(p_node)), "CollisionPolygon2D") { } diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 2754aeed06..f77016c1d6 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -586,8 +586,10 @@ struct CanvasItemPlotCurve { Color color1; Color color2; - CanvasItemPlotCurve(CanvasItem &p_ci, Color p_color1, Color p_color2) - : ci(p_ci), color1(p_color1), color2(p_color2) {} + CanvasItemPlotCurve(CanvasItem &p_ci, Color p_color1, Color p_color2) : + ci(p_ci), + color1(p_color1), + color2(p_color2) {} void operator()(Vector2 pos0, Vector2 pos1, bool in_definition) { ci.draw_line(pos0, pos1, in_definition ? color1 : color2); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index ed04c90cc5..558f44769d 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -235,29 +235,34 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from) { Ref<Material> material = p_from; ERR_FAIL_COND_V(material.is_null(), Ref<Texture>()); - VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid()); + if (material->get_shader_mode() == Shader::MODE_SPATIAL) { - VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture + VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid()); - preview_done = false; - VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant()); + VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture - while (!preview_done) { - OS::get_singleton()->delay_usec(10); - } + preview_done = false; + VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant()); - Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture); - VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID()); + while (!preview_done) { + OS::get_singleton()->delay_usec(10); + } - ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>()); + Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture); + VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID()); - int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); - thumbnail_size *= EDSCALE; - img->convert(Image::FORMAT_RGBA8); - img->resize(thumbnail_size, thumbnail_size); - Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); - ptex->create_from_image(img, 0); - return ptex; + ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>()); + + int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); + thumbnail_size *= EDSCALE; + img->convert(Image::FORMAT_RGBA8); + img->resize(thumbnail_size, thumbnail_size); + Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); + ptex->create_from_image(img, 0); + return ptex; + } + + return Ref<Texture>(); } EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp index 51fa488b43..04d8519b2f 100644 --- a/editor/plugins/line_2d_editor_plugin.cpp +++ b/editor/plugins/line_2d_editor_plugin.cpp @@ -61,10 +61,10 @@ void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, con undo_redo->add_undo_method(node, "set_points", p_previous); } -Line2DEditor::Line2DEditor(EditorNode *p_editor) - : AbstractPolygon2DEditor(p_editor) { +Line2DEditor::Line2DEditor(EditorNode *p_editor) : + AbstractPolygon2DEditor(p_editor) { } -Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) - : AbstractPolygon2DEditorPlugin(p_node, memnew(Line2DEditor(p_node)), "Line2D") { +Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) : + AbstractPolygon2DEditorPlugin(p_node, memnew(Line2DEditor(p_node)), "Line2D") { } diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp index 84fc0cecf2..9d116349c0 100644 --- a/editor/plugins/mesh_instance_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_editor_plugin.cpp @@ -195,7 +195,139 @@ void MeshInstanceEditor::_menu_option(int p_option) { outline_dialog->popup_centered(Vector2(200, 90)); } break; + case MENU_OPTION_CREATE_UV2: { + + Ref<ArrayMesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh.")); + err_dialog->popup_centered_minsize(); + return; + } + + Error err = mesh->lightmap_unwrap(node->get_global_transform()); + if (err != OK) { + err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?")); + err_dialog->popup_centered_minsize(); + return; + } + + } break; + case MENU_OPTION_DEBUG_UV1: { + Ref<Mesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("No mesh to debug.")); + err_dialog->popup_centered_minsize(); + return; + } + _create_uv_lines(0); + } break; + case MENU_OPTION_DEBUG_UV2: { + Ref<Mesh> mesh = node->get_mesh(); + if (!mesh.is_valid()) { + err_dialog->set_text(TTR("No mesh to debug.")); + err_dialog->popup_centered_minsize(); + return; + } + _create_uv_lines(1); + } break; + } +} + +struct MeshInstanceEditorEdgeSort { + + Vector2 a; + Vector2 b; + + bool operator<(const MeshInstanceEditorEdgeSort &p_b) const { + if (a == p_b.a) + return b < p_b.b; + else + return a < p_b.a; + } + + MeshInstanceEditorEdgeSort() {} + MeshInstanceEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) { + if (p_a < p_b) { + a = p_a; + b = p_b; + } else { + b = p_a; + a = p_b; + } + } +}; + +void MeshInstanceEditor::_create_uv_lines(int p_layer) { + + Ref<Mesh> mesh = node->get_mesh(); + ERR_FAIL_COND(!mesh.is_valid()); + + Set<MeshInstanceEditorEdgeSort> edges; + uv_lines.clear(); + for (int i = 0; i < mesh->get_surface_count(); i++) { + if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) + continue; + Array a = mesh->surface_get_arrays(i); + + PoolVector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2]; + if (uv.size() == 0) { + err_dialog->set_text(TTR("Model has no UV in this layer")); + err_dialog->popup_centered_minsize(); + return; + } + + PoolVector<Vector2>::Read r = uv.read(); + + PoolVector<int> indices = a[Mesh::ARRAY_INDEX]; + PoolVector<int>::Read ri; + + int ic; + bool use_indices; + + if (indices.size()) { + ic = indices.size(); + ri = indices.read(); + use_indices = true; + } else { + ic = uv.size(); + use_indices = false; + } + + for (int j = 0; j < ic; j += 3) { + + for (int k = 0; k < 3; k++) { + + MeshInstanceEditorEdgeSort edge; + if (use_indices) { + edge.a = r[ri[j + k]]; + edge.b = r[ri[j + ((k + 1) % 3)]]; + } else { + edge.a = r[j + k]; + edge.b = r[j + ((k + 1) % 3)]; + } + + if (edges.has(edge)) + continue; + + uv_lines.push_back(edge.a); + uv_lines.push_back(edge.b); + edges.insert(edge); + } + } } + + debug_uv_dialog->popup_centered_minsize(); +} + +void MeshInstanceEditor::_debug_uv_draw() { + + if (uv_lines.size() == 0) + return; + + debug_uv->set_clip_contents(true); + debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), Color(0.2, 0.2, 0.0)); + debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size()); + debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7)); } void MeshInstanceEditor::_create_outline_mesh() { @@ -244,6 +376,7 @@ void MeshInstanceEditor::_bind_methods() { ClassDB::bind_method("_menu_option", &MeshInstanceEditor::_menu_option); ClassDB::bind_method("_create_outline_mesh", &MeshInstanceEditor::_create_outline_mesh); + ClassDB::bind_method("_debug_uv_draw", &MeshInstanceEditor::_debug_uv_draw); } MeshInstanceEditor::MeshInstanceEditor() { @@ -263,6 +396,10 @@ MeshInstanceEditor::MeshInstanceEditor() { options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Outline Mesh.."), MENU_OPTION_CREATE_OUTLINE_MESH); + options->get_popup()->add_separator(); + options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1); + options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2); + options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2); options->get_popup()->connect("id_pressed", this, "_menu_option"); @@ -286,6 +423,14 @@ MeshInstanceEditor::MeshInstanceEditor() { err_dialog = memnew(AcceptDialog); add_child(err_dialog); + + debug_uv_dialog = memnew(AcceptDialog); + debug_uv_dialog->set_title("UV Channel Debug"); + add_child(debug_uv_dialog); + debug_uv = memnew(Control); + debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE); + debug_uv->connect("draw", this, "_debug_uv_draw"); + debug_uv_dialog->add_child(debug_uv); } void MeshInstanceEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/mesh_instance_editor_plugin.h b/editor/plugins/mesh_instance_editor_plugin.h index fa851458ce..68c149f98a 100644 --- a/editor/plugins/mesh_instance_editor_plugin.h +++ b/editor/plugins/mesh_instance_editor_plugin.h @@ -47,6 +47,9 @@ class MeshInstanceEditor : public Node { MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE, MENU_OPTION_CREATE_NAVMESH, MENU_OPTION_CREATE_OUTLINE_MESH, + MENU_OPTION_CREATE_UV2, + MENU_OPTION_DEBUG_UV1, + MENU_OPTION_DEBUG_UV2, }; MeshInstance *node; @@ -58,11 +61,18 @@ class MeshInstanceEditor : public Node { AcceptDialog *err_dialog; + AcceptDialog *debug_uv_dialog; + Control *debug_uv; + Vector<Vector2> uv_lines; + void _menu_option(int p_option); void _create_outline_mesh(); + void _create_uv_lines(int p_layer); friend class MeshInstanceEditorPlugin; + void _debug_uv_draw(); + protected: void _node_removed(Node *p_node); static void _bind_methods(); diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp index 6560a8dac7..36c608310b 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.cpp +++ b/editor/plugins/navigation_polygon_editor_plugin.cpp @@ -120,10 +120,10 @@ void NavigationPolygonEditor::_create_resource() { _menu_option(MODE_CREATE); } -NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) - : AbstractPolygon2DEditor(p_editor) { +NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) : + AbstractPolygon2DEditor(p_editor) { } -NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) - : AbstractPolygon2DEditorPlugin(p_node, memnew(NavigationPolygonEditor(p_node)), "NavigationPolygonInstance") { +NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) : + AbstractPolygon2DEditorPlugin(p_node, memnew(NavigationPolygonEditor(p_node)), "NavigationPolygonInstance") { } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index ebb5f57e99..25e734187d 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -459,8 +459,8 @@ Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const { return p_target; } -Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) - : AbstractPolygon2DEditor(p_editor) { +Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : + AbstractPolygon2DEditor(p_editor) { snap_step = Vector2(10, 10); use_snap = false; @@ -609,6 +609,6 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) uv_edit_draw->set_clip_contents(true); } -Polygon2DEditorPlugin::Polygon2DEditorPlugin(EditorNode *p_node) - : AbstractPolygon2DEditorPlugin(p_node, memnew(Polygon2DEditor(p_node)), "Polygon2D") { +Polygon2DEditorPlugin::Polygon2DEditorPlugin(EditorNode *p_node) : + AbstractPolygon2DEditorPlugin(p_node, memnew(Polygon2DEditor(p_node)), "Polygon2D") { } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 3c2d52c128..c02b3458e5 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -586,6 +586,12 @@ void ScriptEditor::_close_docs_tab() { } } +void ScriptEditor::_copy_script_path() { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(tab_container->get_current_tab())); + Ref<Script> script = se->get_edited_script(); + OS::get_singleton()->set_clipboard(script->get_path()); +} + void ScriptEditor::_close_other_tabs() { int child_count = tab_container->get_child_count(); @@ -1026,6 +1032,9 @@ void ScriptEditor::_menu_option(int p_option) { _close_current_tab(); } } break; + case FILE_COPY_PATH: { + _copy_script_path(); + } break; case CLOSE_DOCS: { _close_docs_tab(); } break; @@ -2175,6 +2184,7 @@ void ScriptEditor::_make_script_list_context_menu() { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_all"), CLOSE_ALL); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_other_tabs"), CLOSE_OTHER_TABS); context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/copy_path"), FILE_COPY_PATH); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); Ref<Script> scr = se->get_edited_script(); @@ -2507,6 +2517,7 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method("_help_search", &ScriptEditor::_help_search); ClassDB::bind_method("_help_index", &ScriptEditor::_help_index); ClassDB::bind_method("_save_history", &ScriptEditor::_save_history); + ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path); ClassDB::bind_method("_breaked", &ScriptEditor::_breaked); ClassDB::bind_method("_show_debugger", &ScriptEditor::_show_debugger); @@ -2626,6 +2637,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL); file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), FILE_TOOL_RELOAD_SOFT); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH); file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Prev"), KEY_MASK_ALT | KEY_LEFT), WINDOW_PREV); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 77ca4bc9d9..ffd42d18ca 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -137,6 +137,7 @@ class ScriptEditor : public PanelContainer { CLOSE_ALL, CLOSE_OTHER_TABS, TOGGLE_SCRIPTS_PANEL, + FILE_COPY_PATH, FILE_TOOL_RELOAD, FILE_TOOL_RELOAD_SOFT, DEBUG_NEXT, @@ -255,6 +256,8 @@ class ScriptEditor : public PanelContainer { void _close_other_tabs(); void _close_all_tabs(); + void _copy_script_path(); + void _ask_close_current_unsaved_tab(ScriptEditorBase *current); bool grab_focus_block; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 3a443e1bf7..95f2739927 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -96,10 +96,10 @@ void ScriptTextEditor::_load_theme_settings() { Color member_variable_color = EDITOR_DEF("text_editor/highlighting/member_variable_color", Color(0.9, 0.3, 0.3)); Color mark_color = EDITOR_DEF("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4)); Color breakpoint_color = EDITOR_DEF("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2)); + Color code_folding_color = EDITOR_DEF("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8)); Color search_result_color = EDITOR_DEF("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1)); Color search_result_border_color = EDITOR_DEF("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1)); Color symbol_color = EDITOR_DEF("text_editor/highlighting/symbol_color", Color::hex(0x005291ff)); - Color keyword_color = EDITOR_DEF("text_editor/highlighting/keyword_color", Color(0.5, 0.0, 0.2)); Color basetype_color = EDITOR_DEF("text_editor/highlighting/base_type_color", Color(0.3, 0.3, 0.0)); Color type_color = EDITOR_DEF("text_editor/highlighting/engine_type_color", Color(0.0, 0.2, 0.4)); @@ -137,6 +137,7 @@ void ScriptTextEditor::_load_theme_settings() { member_variable_color = tm->get_color("text_editor/theme/member_variable_color", "Editor"); mark_color = tm->get_color("text_editor/theme/mark_color", "Editor"); breakpoint_color = tm->get_color("text_editor/theme/breakpoint_color", "Editor"); + code_folding_color = tm->get_color("text_editor/theme/code_folding_color", "Editor"); search_result_color = tm->get_color("text_editor/theme/search_result_color", "Editor"); search_result_border_color = tm->get_color("text_editor/theme/search_result_border_color", "Editor"); } @@ -160,8 +161,9 @@ void ScriptTextEditor::_load_theme_settings() { text_edit->add_color_override("number_color", number_color); text_edit->add_color_override("function_color", function_color); text_edit->add_color_override("member_variable_color", member_variable_color); - text_edit->add_color_override("mark_color", mark_color); text_edit->add_color_override("breakpoint_color", breakpoint_color); + text_edit->add_color_override("mark_color", mark_color); + text_edit->add_color_override("code_folding_color", code_folding_color); text_edit->add_color_override("search_result_color", search_result_color); text_edit->add_color_override("search_result_border_color", search_result_border_color); text_edit->add_color_override("symbol_color", symbol_color); @@ -1013,14 +1015,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); } break; - case EDIT_FOLD_LINE: { - - tx->fold_line(tx->cursor_get_line()); - tx->update(); - } break; - case EDIT_UNFOLD_LINE: { + case EDIT_TOGGLE_FOLD_LINE: { - tx->unfold_line(tx->cursor_get_line()); + tx->toggle_fold_line(tx->cursor_get_line()); tx->update(); } break; case EDIT_FOLD_ALL_LINES: { @@ -1509,17 +1506,15 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p if (p_selection) { context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); } - if (p_can_fold) { - // can fold - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); - } else if (p_is_folded) { - // can unfold - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); - } + if (p_can_fold || p_is_folded) + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + if (p_color) { context_menu->add_separator(); context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR); @@ -1583,9 +1578,8 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); edit_menu->get_popup()->add_separator(); #ifdef OSX_ENABLED @@ -1664,8 +1658,7 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), 0); ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD | KEY_K); ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_B); - ED_SHORTCUT("script_text_editor/fold_line", TTR("Fold Line"), KEY_MASK_ALT | KEY_LEFT); - ED_SHORTCUT("script_text_editor/unfold_line", TTR("Unfold Line"), KEY_MASK_ALT | KEY_RIGHT); + ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KEY_MASK_ALT | KEY_F); ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), 0); ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0); #ifdef OSX_ENABLED diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 722015ef3e..e3b81e7c3f 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -91,8 +91,7 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_TO_UPPERCASE, EDIT_TO_LOWERCASE, EDIT_CAPITALIZE, - EDIT_FOLD_LINE, - EDIT_UNFOLD_LINE, + EDIT_TOGGLE_FOLD_LINE, EDIT_FOLD_ALL_LINES, EDIT_UNFOLD_ALL_LINES, SEARCH_FIND, diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 49e4642049..b390070b4a 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -81,6 +81,7 @@ void ShaderTextEditor::_load_theme_settings() { Color member_variable_color = EDITOR_DEF("text_editor/highlighting/member_variable_color", Color(0.9, 0.3, 0.3)); Color mark_color = EDITOR_DEF("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4)); Color breakpoint_color = EDITOR_DEF("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2)); + Color code_folding_color = EDITOR_DEF("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8)); Color search_result_color = EDITOR_DEF("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1)); Color search_result_border_color = EDITOR_DEF("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1)); Color symbol_color = EDITOR_DEF("text_editor/highlighting/symbol_color", Color::hex(0x005291ff)); @@ -122,6 +123,7 @@ void ShaderTextEditor::_load_theme_settings() { member_variable_color = tm->get_color("text_editor/theme/member_variable_color", "Editor"); mark_color = tm->get_color("text_editor/theme/mark_color", "Editor"); breakpoint_color = tm->get_color("text_editor/theme/breakpoint_color", "Editor"); + code_folding_color = tm->get_color("text_editor/theme/code_folding_color", "Editor"); search_result_color = tm->get_color("text_editor/theme/search_result_color", "Editor"); search_result_border_color = tm->get_color("text_editor/theme/search_result_border_color", "Editor"); } @@ -147,6 +149,7 @@ void ShaderTextEditor::_load_theme_settings() { get_text_edit()->add_color_override("member_variable_color", member_variable_color); get_text_edit()->add_color_override("mark_color", mark_color); get_text_edit()->add_color_override("breakpoint_color", breakpoint_color); + get_text_edit()->add_color_override("code_folding_color", code_folding_color); get_text_edit()->add_color_override("search_result_color", search_result_color); get_text_edit()->add_color_override("search_result_border_color", search_result_border_color); get_text_edit()->add_color_override("symbol_color", symbol_color); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 60d7e59991..00488a2a88 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -508,7 +508,8 @@ public: } else if (current->has_setting("application/config/name")) { project_name->set_text(current->get("application/config/name")); } - project_name->grab_focus(); + + project_name->call_deferred("grab_focus"); create_dir->hide(); status_btn->hide(); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 900f7625bc..76fd20ca12 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -1776,7 +1776,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { //translations TabContainer *translations = memnew(TabContainer); - translations->add_style_override("panel", memnew(StyleBoxEmpty)); translations->set_tab_align(TabContainer::ALIGN_LEFT); translations->set_name(TTR("Localization")); tab_container->add_child(translations); @@ -1888,19 +1887,14 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { translation_filter->connect("item_edited", this, "_translation_filter_option_changed"); } - { - autoload_settings = memnew(EditorAutoloadSettings); - autoload_settings->set_name(TTR("AutoLoad")); - tab_container->add_child(autoload_settings); - autoload_settings->connect("autoload_changed", this, "_settings_changed"); - } + autoload_settings = memnew(EditorAutoloadSettings); + autoload_settings->set_name(TTR("AutoLoad")); + tab_container->add_child(autoload_settings); + autoload_settings->connect("autoload_changed", this, "_settings_changed"); - { - - plugin_settings = memnew(EditorPluginSettings); - plugin_settings->set_name(TTR("Plugins")); - tab_container->add_child(plugin_settings); - } + plugin_settings = memnew(EditorPluginSettings); + plugin_settings->set_name(TTR("Plugins")); + tab_container->add_child(plugin_settings); timer = memnew(Timer); timer->set_wait_time(1.5); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 6f9454be2c..446a0ea35d 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -430,24 +430,19 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: } else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || hint == PROPERTY_HINT_LAYERS_2D_RENDER || hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || hint == PROPERTY_HINT_LAYERS_3D_RENDER) { - String title; String basename; switch (hint) { case PROPERTY_HINT_LAYERS_2D_RENDER: basename = "layer_names/2d_render"; - title = "2D Render Layers"; break; case PROPERTY_HINT_LAYERS_2D_PHYSICS: basename = "layer_names/2d_physics"; - title = "2D Physics Layers"; break; case PROPERTY_HINT_LAYERS_3D_RENDER: basename = "layer_names/3d_render"; - title = "3D Render Layers"; break; case PROPERTY_HINT_LAYERS_3D_PHYSICS: basename = "layer_names/3d_physics"; - title = "3D Physics Layers"; break; } @@ -469,11 +464,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: show(); - value_label[0]->set_text(title); - value_label[0]->show(); - value_label[0]->set_position(Vector2(4, 4) * EDSCALE); - - checks20gc->set_position(Vector2(4, 4) * EDSCALE + Vector2(0, value_label[0]->get_size().height + 4 * EDSCALE)); + checks20gc->set_position(Vector2(4, 4) * EDSCALE); checks20gc->set_size(checks20gc->get_minimum_size()); set_size(Vector2(4, 4) * EDSCALE + checks20gc->get_position() + checks20gc->get_size()); @@ -2101,6 +2092,23 @@ bool PropertyEditor::_is_property_different(const Variant &p_current, const Vari return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig)); } +bool PropertyEditor::_is_instanced_node_with_original_property_different(const String &p_name, TreeItem *item) { + bool mbi = _might_be_in_instance(); + if (mbi) { + Variant vorig; + Dictionary d = item->get_metadata(0); + int usage = d.has("usage") ? int(int(d["usage"]) & (PROPERTY_USAGE_STORE_IF_NONONE | PROPERTY_USAGE_STORE_IF_NONZERO)) : 0; + if (_get_instanced_node_original_property(p_name, vorig) || usage) { + Variant v = obj->get(p_name); + + if (_is_property_different(v, vorig, usage)) { + return true; + } + } + } + return false; +} + TreeItem *PropertyEditor::find_item(TreeItem *p_item, const String &p_name) { if (!p_item) @@ -2360,6 +2368,10 @@ void PropertyEditor::_check_reload_status(const String &p_name, TreeItem *item) } } + if (_is_instanced_node_with_original_property_different(p_name, item)) { + has_reload = true; + } + if (obj->call("property_can_revert", p_name).operator bool()) { has_reload = true; @@ -2665,18 +2677,14 @@ TreeItem *PropertyEditor::get_parent_node(String p_path, HashMap<String, TreeIte item->set_editable(1, false); item->set_selectable(1, subsection_selectable); - if (use_folding || folding_behaviour != FB_UNDEFINED) { // Even if you disabled folding (expand all by default), you still can collapse all manually. + if (use_folding) { // if (!obj->editor_is_section_unfolded(p_path)) { updating_folding = true; - if (folding_behaviour == FB_COLLAPSEALL) - item->set_collapsed(true); - else if (folding_behaviour == FB_EXPANDALL || is_expandall_enabled) - item->set_collapsed(false); - else - item->set_collapsed(true); + item->set_collapsed(true); updating_folding = false; } item->set_metadata(0, p_path); + foldable_property_cache.push_back(p_path); } if (item->get_parent() == root) { @@ -2725,6 +2733,7 @@ void PropertyEditor::refresh() { void PropertyEditor::update_tree() { tree->clear(); + foldable_property_cache.clear(); if (!obj) return; @@ -3512,20 +3521,9 @@ void PropertyEditor::update_tree() { bool has_reload = false; - bool mbi = _might_be_in_instance(); - if (mbi) { - - Variant vorig; - Dictionary d = item->get_metadata(0); - int usage = d.has("usage") ? int(int(d["usage"]) & (PROPERTY_USAGE_STORE_IF_NONONE | PROPERTY_USAGE_STORE_IF_NONZERO)) : 0; - if (_get_instanced_node_original_property(p.name, vorig) || usage) { - Variant v = obj->get(p.name); - - if (_is_property_different(v, vorig, usage)) { - item->add_button(1, get_icon("ReloadSmall", "EditorIcons"), 3); - has_reload = true; - } - } + if (_is_instanced_node_with_original_property_different(p.name, item)) { + item->add_button(1, get_icon("ReloadSmall", "EditorIcons"), 3); + has_reload = true; } if (obj->call("property_can_revert", p.name).operator bool()) { @@ -3545,7 +3543,7 @@ void PropertyEditor::update_tree() { } } - if (mbi && !has_reload && item->get_cell_mode(1) == TreeItem::CELL_MODE_RANGE && item->get_text(1) == String()) { + if (_might_be_in_instance() && !has_reload && item->get_cell_mode(1) == TreeItem::CELL_MODE_RANGE && item->get_text(1) == String()) { item->add_button(1, get_icon("ReloadEmpty", "EditorIcons"), 3, true); } } @@ -3733,8 +3731,8 @@ void PropertyEditor::_item_edited() { _edit_set(name, item->get_text(1), refresh_all); } } break; - // math types + // math types case Variant::VECTOR3: { } break; @@ -4212,29 +4210,29 @@ void PropertyEditor::set_subsection_selectable(bool p_selectable) { update_tree(); } -bool PropertyEditor::is_expand_all_properties_enabled() const { - - return (use_folding == false); -} - void PropertyEditor::set_use_folding(bool p_enable) { use_folding = p_enable; tree->set_hide_folding(false); } -void PropertyEditor::collapse_all_parent_nodes() { - - folding_behaviour = FB_COLLAPSEALL; +void PropertyEditor::collapse_all_folding() { + if (!obj) + return; + for (List<String>::Element *E = foldable_property_cache.front(); E; E = E->next()) { + obj->editor_set_section_unfold(E->get(), false); + } update_tree(); - folding_behaviour = FB_UNDEFINED; } -void PropertyEditor::expand_all_parent_nodes() { +void PropertyEditor::expand_all_folding() { - folding_behaviour = FB_EXPANDALL; + if (!obj) + return; + for (List<String>::Element *E = foldable_property_cache.front(); E; E = E->next()) { + obj->editor_set_section_unfold(E->get(), true); + } update_tree(); - folding_behaviour = FB_UNDEFINED; } PropertyEditor::PropertyEditor() { @@ -4309,8 +4307,6 @@ PropertyEditor::PropertyEditor() { subsection_selectable = false; property_selectable = false; show_type_icons = false; // maybe one day will return. - folding_behaviour = FB_UNDEFINED; - is_expandall_enabled = bool(EDITOR_DEF("interface/editor/expand_all_properties", true)); } PropertyEditor::~PropertyEditor() { diff --git a/editor/property_editor.h b/editor/property_editor.h index a337a05e46..f684f5768d 100644 --- a/editor/property_editor.h +++ b/editor/property_editor.h @@ -203,18 +203,9 @@ class PropertyEditor : public Control { bool hide_script; bool use_folding; bool property_selectable; - bool is_expandall_enabled; - bool updating_folding; - enum FOLDING_BEHAVIOUR { - FB_UNDEFINED, - FB_COLLAPSEALL, - FB_EXPANDALL, - FB_EXPANDALL_FORCE - }; - FOLDING_BEHAVIOUR folding_behaviour; - + List<String> foldable_property_cache; HashMap<String, String> pending; String selected_property; @@ -253,6 +244,7 @@ class PropertyEditor : public Control { bool _might_be_in_instance(); bool _get_instanced_node_original_property(const StringName &p_prop, Variant &value); bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage = 0); + bool _is_instanced_node_with_original_property_different(const String &p_name, TreeItem *item); void _refresh_item(TreeItem *p_item); void _set_range_def(Object *p_item, String prop, float p_frame); @@ -314,10 +306,8 @@ public: void set_use_folding(bool p_enable); - bool is_expand_all_properties_enabled() const; - - void collapse_all_parent_nodes(); - void expand_all_parent_nodes(); + void collapse_all_folding(); + void expand_all_folding(); PropertyEditor(); ~PropertyEditor(); }; |