diff options
Diffstat (limited to 'editor/editor_node.cpp')
-rw-r--r-- | editor/editor_node.cpp | 550 |
1 files changed, 433 insertions, 117 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 9169227e8a..f7a952d5cc 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -65,6 +65,7 @@ #include "editor/import/resource_importer_obj.h" #include "editor/import/resource_importer_scene.h" #include "editor/import/resource_importer_texture.h" +#include "editor/import/resource_importer_texture_atlas.h" #include "editor/import/resource_importer_wav.h" #include "editor/plugins/animation_blend_space_1d_editor.h" #include "editor/plugins/animation_blend_space_2d_editor.h" @@ -81,6 +82,7 @@ #include "editor/plugins/collision_polygon_2d_editor_plugin.h" #include "editor/plugins/collision_polygon_editor_plugin.h" #include "editor/plugins/collision_shape_2d_editor_plugin.h" +#include "editor/plugins/cpu_particles_2d_editor_plugin.h" #include "editor/plugins/cpu_particles_editor_plugin.h" #include "editor/plugins/curve_editor_plugin.h" #include "editor/plugins/editor_preview_plugins.h" @@ -136,10 +138,10 @@ void EditorNode::_update_scene_tabs() { Ref<Texture> script_icon = gui_base->get_icon("Script", "EditorIcons"); for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { - String type = editor_data.get_scene_type(i); + Node *type_node = editor_data.get_edited_scene_root(i); Ref<Texture> icon; - if (type != String()) { - icon = get_class_icon(type, "Node"); + if (type_node) { + icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node"); } int current = editor_data.get_edited_scene(); @@ -291,6 +293,8 @@ void EditorNode::_notification(int p_what) { get_tree()->get_root()->set_as_audio_listener_2d(false); get_tree()->set_auto_accept_quit(false); get_tree()->connect("files_dropped", this, "_dropped_files"); + + /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } if (p_what == NOTIFICATION_EXIT_TREE) { @@ -303,9 +307,17 @@ void EditorNode::_notification(int p_what) { VisualServer::get_singleton()->viewport_set_hide_canvas(get_scene_root()->get_viewport_rid(), true); VisualServer::get_singleton()->viewport_set_disable_environment(get_viewport()->get_viewport_rid(), true); - _editor_select(EDITOR_3D); + feature_profile_manager->notify_changed(); + + if (!main_editor_buttons[EDITOR_3D]->is_visible()) { //may be hidden due to feature profile + _editor_select(EDITOR_2D); + } else { + _editor_select(EDITOR_3D); + } + _update_debug_options(); - _load_docks(); + + /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_IN) { @@ -326,7 +338,6 @@ void EditorNode::_notification(int p_what) { gui_base->set_theme(theme); gui_base->add_style_override("panel", gui_base->get_stylebox("Background", "EditorStyles")); - play_button_panel->add_style_override("panel", gui_base->get_stylebox("PlayButtonPanel", "EditorStyles")); scene_root_parent->add_style_override("panel", gui_base->get_stylebox("Content", "EditorStyles")); bottom_panel->add_style_override("panel", gui_base->get_stylebox("panel", "TabContainer")); scene_tabs->add_style_override("tab_fg", gui_base->get_stylebox("SceneTabFG", "EditorStyles")); @@ -494,7 +505,7 @@ void EditorNode::_fs_changed() { } } - get_tree()->quit(); + _exit_editor(); } } @@ -528,14 +539,17 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) { void EditorNode::_sources_changed(bool p_exist) { if (waiting_for_first_scan) { + waiting_for_first_scan = false; + + EditorResourcePreview::get_singleton()->start(); //start previes now that it's safe + + _load_docks(); if (defer_load_scene != "") { load_scene(defer_load_scene); defer_load_scene = ""; } - - waiting_for_first_scan = false; } } @@ -552,11 +566,14 @@ void EditorNode::_editor_select_next() { int editor = _get_current_main_editor(); - if (editor == editor_table.size() - 1) { - editor = 0; - } else { - editor++; - } + do { + if (editor == editor_table.size() - 1) { + editor = 0; + } else { + editor++; + } + } while (main_editor_buttons[editor]->is_visible()); + _editor_select(editor); } @@ -564,11 +581,14 @@ void EditorNode::_editor_select_prev() { int editor = _get_current_main_editor(); - if (editor == 0) { - editor = editor_table.size() - 1; - } else { - editor--; - } + do { + if (editor == 0) { + editor = editor_table.size() - 1; + } else { + editor--; + } + } while (main_editor_buttons[editor]->is_visible()); + _editor_select(editor); } @@ -614,7 +634,11 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); if (err != OK) { - show_accept(TTR("Error saving resource!"), TTR("OK")); + if (ResourceLoader::is_imported(p_resource->get_path())) { + show_accept(TTR("Imported resources can't be saved."), TTR("OK")); + } else { + show_accept(TTR("Error saving resource!"), TTR("OK")); + } return; } @@ -634,6 +658,18 @@ void EditorNode::save_resource(const Ref<Resource> &p_resource) { void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path) { + { + String path = p_resource->get_path(); + int srpos = path.find("::"); + if (srpos != -1) { + String base = path.substr(0, srpos); + if (!get_edited_scene() || get_edited_scene()->get_filename() != base) { + show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first.")); + return; + } + } + } + file->set_mode(EditorFileDialog::MODE_SAVE_FILE); saving_resource = p_resource; @@ -881,15 +917,16 @@ bool EditorNode::_find_and_save_edited_subresources(Object *obj, Map<RES, bool> Dictionary d = obj->get(E->get().name); List<Variant> keys; d.get_key_list(&keys); - for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { + for (List<Variant>::Element *F = keys.front(); F; F = F->next()) { - Variant v = d[E->get()]; + Variant v = d[F->get()]; RES res = v; if (_find_and_save_resource(res, processed, flags)) ret_changed = true; } } break; - default: {} + default: { + } } } @@ -952,6 +989,9 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { } if (img.is_valid()) { + + img = img->duplicate(); + save.step(TTR("Creating Thumbnail"), 2); save.step(TTR("Creating Thumbnail"), 3); @@ -1015,6 +1055,70 @@ bool EditorNode::_validate_scene_recursive(const String &p_filename, Node *p_nod return false; } +static bool _find_edited_resources(const Ref<Resource> &p_resource, Set<Ref<Resource> > &edited_resources) { + + if (p_resource->is_edited()) { + edited_resources.insert(p_resource); + return true; + } + + List<PropertyInfo> plist; + + p_resource->get_property_list(&plist); + + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + if (E->get().type == Variant::OBJECT && E->get().usage & PROPERTY_USAGE_STORAGE && !(E->get().usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT)) { + RES res = p_resource->get(E->get().name); + if (res.is_null()) { + continue; + } + if (res->get_path().is_resource_file()) { //not a subresource, continue + continue; + } + if (_find_edited_resources(res, edited_resources)) { + return true; + } + } + } + + return false; +} + +int EditorNode::_save_external_resources() { + //save external resources and its subresources if any was modified + + int flg = 0; + if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) + flg |= ResourceSaver::FLAG_COMPRESS; + flg |= ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; + + Set<Ref<Resource> > edited_subresources; + int saved = 0; + List<Ref<Resource> > cached; + ResourceCache::get_cached_resources(&cached); + for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) { + + Ref<Resource> res = E->get(); + if (!res->get_path().is_resource_file()) + continue; + //not only check if this resourec is edited, check contained subresources too + if (_find_edited_resources(res, edited_subresources)) { + ResourceSaver::save(res->get_path(), res, flg); + saved++; + } + } + + // clear later, because user may have put the same subresource in two different resources, + // which will be shared until the next reload + + for (Set<Ref<Resource> >::Element *E = edited_subresources.front(); E; E = E->next()) { + Ref<Resource> res = E->get(); + res->set_edited(false); + } + + return saved; +} + void EditorNode::_save_scene(String p_file, int idx) { Node *scene = editor_data.get_edited_scene_root(idx); @@ -1073,22 +1177,8 @@ void EditorNode::_save_scene(String p_file, int idx) { flg |= ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; err = ResourceSaver::save(p_file, sdata, flg); - //Map<RES, bool> processed; - //this method is slow and not always works, deprecating - //_save_edited_subresources(scene, processed, flg); - { //instead, just find globally unsaved subresources and save them - - List<Ref<Resource> > cached; - ResourceCache::get_cached_resources(&cached); - for (List<Ref<Resource> >::Element *E = cached.front(); E; E = E->next()) { - - Ref<Resource> res = E->get(); - if (res->is_edited() && res->get_path().is_resource_file()) { - ResourceSaver::save(res->get_path(), res, flg); - res->set_edited(false); - } - } - } + + _save_external_resources(); editor_data.save_editor_external_data(); if (err == OK) { @@ -1108,19 +1198,22 @@ void EditorNode::_save_scene(String p_file, int idx) { } } -void EditorNode::save_all_scenes_and_restart() { +void EditorNode::save_all_scenes() { _menu_option_confirm(RUN_STOP, true); - exiting = true; - _save_all_scenes(); +} + +void EditorNode::restart_editor() { + + exiting = true; String to_reopen; if (get_tree()->get_edited_scene_root()) { to_reopen = get_tree()->get_edited_scene_root()->get_filename(); } - get_tree()->quit(); + _exit_editor(); String exec = OS::get_singleton()->get_executable_path(); List<String> args; @@ -1214,6 +1307,7 @@ void EditorNode::_dialog_action(String p_file) { _save_default_environment(); _save_scene_with_preview(p_file, scene_idx); _add_to_recent_scenes(p_file); + save_layout(); if (scene_idx != -1) _discard_changes(); @@ -1362,25 +1456,71 @@ void EditorNode::_dialog_action(String p_file) { bool EditorNode::item_has_editor(Object *p_object) { + if (_is_class_editor_disabled_by_feature_profile(p_object->get_class())) { + return false; + } + return editor_data.get_subeditors(p_object).size() > 0; } +void EditorNode::edit_item_resource(RES p_resource) { + edit_item(p_resource.ptr()); +} + +bool EditorNode::_is_class_editor_disabled_by_feature_profile(const StringName &p_class) { + + Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile(); + if (profile.is_null()) { + return false; + } + + StringName class_name = p_class; + + while (class_name != StringName()) { + + if (profile->is_class_disabled(class_name)) { + return true; + } + if (profile->is_class_editor_disabled(class_name)) { + return true; + } + class_name = ClassDB::get_parent_class(class_name); + } + + return false; +} + void EditorNode::edit_item(Object *p_object) { Vector<EditorPlugin *> sub_plugins; if (p_object) { + if (_is_class_editor_disabled_by_feature_profile(p_object->get_class())) { + return; + } sub_plugins = editor_data.get_subeditors(p_object); } if (!sub_plugins.empty()) { - _display_top_editors(false); - _set_top_editors(sub_plugins); + bool same = true; + if (sub_plugins.size() == editor_plugins_over->get_plugins_list().size()) { + for (int i = 0; i < sub_plugins.size(); i++) { + if (sub_plugins[i] != editor_plugins_over->get_plugins_list()[i]) { + same = false; + } + } + } else { + same = false; + } + if (!same) { + _display_top_editors(false); + _set_top_editors(sub_plugins); + } _set_editing_top_editors(p_object); _display_top_editors(true); } else { - _hide_top_editors(); + hide_top_editors(); } } @@ -1418,7 +1558,7 @@ void EditorNode::_save_default_environment() { } } -void EditorNode::_hide_top_editors() { +void EditorNode::hide_top_editors() { _display_top_editors(false); @@ -1547,6 +1687,12 @@ void EditorNode::_edit_current() { EditorPlugin *main_plugin = editor_data.get_editor(current_obj); + for (int i = 0; i < editor_table.size(); i++) { + if (editor_table[i] == main_plugin && !main_editor_buttons[i]->is_visible()) { + main_plugin = NULL; //if button is not visible, then no plugin active + } + } + if (main_plugin) { // special case if use of external editor is true @@ -1584,7 +1730,11 @@ void EditorNode::_edit_current() { } } - Vector<EditorPlugin *> sub_plugins = editor_data.get_subeditors(current_obj); + Vector<EditorPlugin *> sub_plugins; + + if (!_is_class_editor_disabled_by_feature_profile(current_obj->get_class())) { + sub_plugins = editor_data.get_subeditors(current_obj); + } if (!sub_plugins.empty()) { _display_top_editors(false); @@ -1592,10 +1742,9 @@ void EditorNode::_edit_current() { _set_top_editors(sub_plugins); _set_editing_top_editors(current_obj); _display_top_editors(true); - } else if (!editor_plugins_over->get_plugins_list().empty()) { - _hide_top_editors(); + hide_top_editors(); } } @@ -1807,7 +1956,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { break; } - } // fallthrough + FALLTHROUGH; + } case SCENE_TAB_CLOSE: case FILE_SAVE_SCENE: { @@ -1826,8 +1976,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { break; } - // fallthrough to save_as - }; + FALLTHROUGH; + } case FILE_SAVE_AS_SCENE: { int scene_idx = (p_option == FILE_SAVE_SCENE || p_option == FILE_SAVE_AS_SCENE) ? -1 : tab_closing; @@ -1835,7 +1985,15 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!scene) { - show_accept(TTR("This operation can't be done without a tree root."), TTR("OK")); + int saved = _save_external_resources(); + String err_text; + if (saved > 0) { + err_text = vformat(TTR("Saved %s modified resource(s)."), itos(saved)); + } else { + err_text = TTR("A root node is required to save the scene."); + } + + show_accept(err_text, TTR("OK")); break; } @@ -2257,6 +2415,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { export_template_manager->popup_manager(); } break; + case SETTINGS_MANAGE_FEATURE_PROFILES: { + + feature_profile_manager->popup_centered_ratio(); + + } break; case SETTINGS_TOGGLE_FULLSCREEN: { OS::get_singleton()->set_window_fullscreen(!OS::get_singleton()->is_window_fullscreen()); @@ -2305,7 +2468,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { ProjectSettings::get_singleton()->set("rendering/quality/driver/driver_name", video_driver_request); ProjectSettings::get_singleton()->save(); - save_all_scenes_and_restart(); + save_all_scenes(); + restart_editor(); } break; default: { if (p_option >= IMPORT_PLUGIN_BASE) { @@ -2356,6 +2520,13 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) { return -1; } +void EditorNode::_exit_editor() { + exiting = true; + resource_preview->stop(); //stop early to avoid crashes + _save_docks(); + get_tree()->quit(); +} + void EditorNode::_discard_changes(const String &p_str) { switch (current_option) { @@ -2383,14 +2554,13 @@ void EditorNode::_discard_changes(const String &p_str) { case FILE_QUIT: { _menu_option_confirm(RUN_STOP, true); - exiting = true; - get_tree()->quit(); + _exit_editor(); + } break; case RUN_PROJECT_MANAGER: { _menu_option_confirm(RUN_STOP, true); - exiting = true; - get_tree()->quit(); + _exit_editor(); String exec = OS::get_singleton()->get_executable_path(); List<String> args; @@ -2433,10 +2603,13 @@ void EditorNode::_editor_select(int p_which) { if (selecting || changing_scene) return; - selecting = true; - ERR_FAIL_INDEX(p_which, editor_table.size()); + if (!main_editor_buttons[p_which]->is_visible()) //button hidden, no editor + return; + + selecting = true; + for (int i = 0; i < main_editor_buttons.size(); i++) { main_editor_buttons[i]->set_pressed(i == p_which); } @@ -2528,6 +2701,7 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan singleton->editor_plugins_over->get_plugins_list().erase(p_editor); singleton->remove_child(p_editor); singleton->editor_data.remove_editor_plugin(p_editor); + singleton->get_editor_plugins_force_input_forwarding()->remove_plugin(p_editor); } void EditorNode::_update_addon_config() { @@ -2568,6 +2742,20 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, Ref<ConfigFile> cf; cf.instance(); String addon_path = "res://addons/" + p_addon + "/plugin.cfg"; + if (!DirAccess::exists(addon_path.get_base_dir())) { + ProjectSettings *ps = ProjectSettings::get_singleton(); + PoolStringArray enabled_plugins = ps->get("editor_plugins/enabled"); + for (int i = 0; i < enabled_plugins.size(); ++i) { + if (enabled_plugins.get(i) == p_addon) { + enabled_plugins.remove(i); + break; + } + } + ps->set("editor_plugins/enabled", enabled_plugins); + ps->save(); + WARN_PRINTS("Addon '" + p_addon + "' failed to load. No directory found. Removing from enabled plugins."); + return; + } Error err = cf->load(addon_path); if (err != OK) { show_warning(vformat(TTR("Unable to enable addon plugin at: '%s' parsing of config failed."), addon_path)); @@ -2759,7 +2947,7 @@ bool EditorNode::is_changing_scene() const { void EditorNode::_clear_undo_history() { - get_undo_redo()->clear_history(); + get_undo_redo()->clear_history(false); } void EditorNode::set_current_scene(int p_idx) { @@ -2960,6 +3148,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b prev_scene->set_disabled(previous_scenes.size() == 0); opening_prev = false; + scene_tree_dock->set_selected(new_scene); ScriptEditor::get_singleton()->get_debugger()->update_live_edit_root(); @@ -3160,6 +3349,7 @@ void EditorNode::register_editor_types() { ClassDB::register_class<EditorProperty>(); ClassDB::register_class<AnimationTrackEditPlugin>(); ClassDB::register_class<ScriptCreateDialog>(); + ClassDB::register_class<EditorFeatureProfile>(); // FIXME: Is this stuff obsolete, or should it be ported to new APIs? ClassDB::register_class<EditorScenePostImport>(); @@ -3228,12 +3418,30 @@ Ref<Texture> EditorNode::get_class_icon(const String &p_class, const String &p_f if (ScriptServer::is_global_class(p_class)) { String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(p_class); RES icon; + if (FileAccess::exists(icon_path)) { icon = ResourceLoader::load(icon_path); + if (icon.is_valid()) + return icon; } - if (!icon.is_valid()) { + + Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class), "Script"); + + while (script.is_valid()) { + String current_icon_path; + script->get_language()->get_global_class_name(script->get_path(), NULL, ¤t_icon_path); + if (FileAccess::exists(current_icon_path)) { + RES texture = ResourceLoader::load(current_icon_path); + if (texture.is_valid()) + return texture; + } + script = script->get_base_script(); + } + + if (icon.is_null()) { icon = gui_base->get_icon(ScriptServer::get_global_class_base(p_class), "EditorIcons"); } + return icon; } @@ -3575,6 +3783,9 @@ void EditorNode::_dock_select_draw() { void EditorNode::_save_docks() { + if (waiting_for_first_scan) { + return; //scanning, do not touch docks + } Ref<ConfigFile> config; config.instance(); @@ -3602,6 +3813,8 @@ void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p } p_layout->set_value(p_section, "dock_filesystem_split", filesystem_dock->get_split_offset()); + p_layout->set_value(p_section, "dock_filesystem_display_mode", filesystem_dock->get_display_mode()); + p_layout->set_value(p_section, "dock_filesystem_file_list_display_mode", filesystem_dock->get_file_list_display_mode()); for (int i = 0; i < vsplits.size(); i++) { @@ -3674,7 +3887,13 @@ void EditorNode::_update_dock_slots_visibility() { } else { for (int i = 0; i < DOCK_SLOT_MAX; i++) { - if (dock_slot[i]->get_tab_count()) + int tabs_visible = 0; + for (int j = 0; j < dock_slot[i]->get_tab_count(); j++) { + if (!dock_slot[i]->get_tab_hidden(j)) { + tabs_visible++; + } + } + if (tabs_visible) dock_slot[i]->show(); else dock_slot[i]->hide(); @@ -3786,11 +4005,20 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String } } - int fs_split_ofs = 0; if (p_layout->has_section_key(p_section, "dock_filesystem_split")) { - fs_split_ofs = p_layout->get_value(p_section, "dock_filesystem_split"); + int fs_split_ofs = p_layout->get_value(p_section, "dock_filesystem_split"); + filesystem_dock->set_split_offset(fs_split_ofs); + } + + if (p_layout->has_section_key(p_section, "dock_filesystem_display_mode")) { + FileSystemDock::DisplayMode dock_filesystem_display_mode = FileSystemDock::DisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_display_mode"))); + filesystem_dock->set_display_mode(dock_filesystem_display_mode); + } + + if (p_layout->has_section_key(p_section, "dock_filesystem_file_list_display_mode")) { + FileSystemDock::FileListDisplayMode dock_filesystem_file_list_display_mode = FileSystemDock::FileListDisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_file_list_display_mode"))); + filesystem_dock->set_file_list_display_mode(dock_filesystem_file_list_display_mode); } - filesystem_dock->set_split_offset(fs_split_ofs); for (int i = 0; i < vsplits.size(); i++) { @@ -3844,6 +4072,7 @@ void EditorNode::_load_open_scenes_from_config(Ref<ConfigFile> p_layout, const S for (int i = 0; i < scenes.size(); i++) { load_scene(scenes[i]); } + save_layout(); restoring_scenes = false; } @@ -4096,7 +4325,13 @@ bool EditorNode::are_bottom_panels_hidden() const { void EditorNode::hide_bottom_panel() { - _bottom_panel_switch(false, 0); + for (int i = 0; i < bottom_panel_items.size(); i++) { + + if (bottom_panel_items[i].control->is_visible()) { + _bottom_panel_switch(false, i); + break; + } + } } void EditorNode::make_bottom_panel_item_visible(Control *p_item) { @@ -4133,7 +4368,7 @@ void EditorNode::remove_bottom_panel_item(Control *p_item) { if (bottom_panel_items[i].control == p_item) { if (p_item->is_visible_in_tree()) { - _bottom_panel_switch(false, 0); + _bottom_panel_switch(false, i); } bottom_panel_vb->remove_child(bottom_panel_items[i].control); bottom_panel_hb_editors->remove_child(bottom_panel_items[i].button); @@ -4153,6 +4388,10 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) { ERR_FAIL_INDEX(p_idx, bottom_panel_items.size()); + if (bottom_panel_items[p_idx].control->is_visible() == p_enable) { + return; + } + if (p_enable) { for (int i = 0; i < bottom_panel_items.size(); i++) { @@ -4173,11 +4412,8 @@ void EditorNode::_bottom_panel_switch(bool p_enable, int p_idx) { } else { bottom_panel->add_style_override("panel", gui_base->get_stylebox("panel", "TabContainer")); - for (int i = 0; i < bottom_panel_items.size(); i++) { - - bottom_panel_items[i].button->set_pressed(false); - bottom_panel_items[i].control->set_visible(false); - } + bottom_panel_items[p_idx].button->set_pressed(false); + bottom_panel_items[p_idx].control->set_visible(false); center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN); center_split->set_collapsed(true); bottom_panel_raise->hide(); @@ -4393,20 +4629,54 @@ void EditorNode::remove_tool_menu_item(const String &p_name) { void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) { - String to_path = ProjectSettings::get_singleton()->globalize_path(get_filesystem_dock()->get_current_path()); - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + String to_path = ProjectSettings::get_singleton()->globalize_path(get_filesystem_dock()->get_selected_path()); + + _add_dropped_files_recursive(p_files, to_path); + + EditorFileSystem::get_singleton()->scan_changes(); +} + +void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, String to_path) { + DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Vector<String> just_copy = String("ttf,otf").split(","); + for (int i = 0; i < p_files.size(); i++) { String from = p_files[i]; + String to = to_path.plus_file(from.get_file()); + + if (dir->dir_exists(from)) { + + Vector<String> sub_files; + + DirAccessRef sub_dir = DirAccess::open(from); + sub_dir->list_dir_begin(); + + String next_file = sub_dir->get_next(); + while (next_file != "") { + if (next_file == "." || next_file == "..") { + next_file = sub_dir->get_next(); + continue; + } + + sub_files.push_back(from.plus_file(next_file)); + next_file = sub_dir->get_next(); + } + + if (!sub_files.empty()) { + dir->make_dir(to); + _add_dropped_files_recursive(sub_files, to); + } + + continue; + } + if (!ResourceFormatImporter::get_singleton()->can_be_imported(from) && (just_copy.find(from.get_extension().to_lower()) == -1)) { continue; } - String to = to_path.plus_file(from.get_file()); dir->copy(from, to); } - EditorFileSystem::get_singleton()->scan_changes(); } void EditorNode::_file_access_close_error_notify(const String &p_str) { @@ -4643,6 +4913,39 @@ void EditorNode::_resource_loaded(RES p_resource, const String &p_path) { singleton->editor_folding.load_resource_folding(p_resource, p_path); } +void EditorNode::_feature_profile_changed() { + + Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile(); + TabContainer *import_tabs = cast_to<TabContainer>(import_dock->get_parent()); + TabContainer *node_tabs = cast_to<TabContainer>(node_dock->get_parent()); + TabContainer *fs_tabs = cast_to<TabContainer>(filesystem_dock->get_parent()); + if (profile.is_valid()) { + + import_tabs->set_tab_hidden(import_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK)); + node_tabs->set_tab_hidden(node_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK)); + fs_tabs->set_tab_hidden(filesystem_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK)); + + main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)); + main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT)); + main_editor_buttons[EDITOR_ASSETLIB]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB)); + if (profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D) || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB) || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB)) { + _editor_select(EDITOR_2D); + } + } else { + + import_tabs->set_tab_hidden(import_dock->get_index(), false); + node_tabs->set_tab_hidden(node_dock->get_index(), false); + fs_tabs->set_tab_hidden(filesystem_dock->get_index(), false); + import_dock->set_visible(true); + node_dock->set_visible(true); + filesystem_dock->set_visible(true); + main_editor_buttons[EDITOR_3D]->set_visible(true); + main_editor_buttons[EDITOR_ASSETLIB]->set_visible(true); + } + + _update_dock_slots_visibility(); +} + void EditorNode::_bind_methods() { ClassDB::bind_method("_menu_option", &EditorNode::_menu_option); @@ -4704,6 +5007,7 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("_clear_undo_history", &EditorNode::_clear_undo_history); ClassDB::bind_method("_dropped_files", &EditorNode::_dropped_files); ClassDB::bind_method("_toggle_distraction_free_mode", &EditorNode::_toggle_distraction_free_mode); + ClassDB::bind_method("edit_item_resource", &EditorNode::edit_item_resource); ClassDB::bind_method(D_METHOD("get_gui_base"), &EditorNode::get_gui_base); ClassDB::bind_method(D_METHOD("_bottom_panel_switch"), &EditorNode::_bottom_panel_switch); @@ -4720,6 +5024,7 @@ void EditorNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_video_driver_selected"), &EditorNode::_video_driver_selected); ClassDB::bind_method(D_METHOD("_resources_changed"), &EditorNode::_resources_changed); + ClassDB::bind_method(D_METHOD("_feature_profile_changed"), &EditorNode::_feature_profile_changed); ADD_SIGNAL(MethodInfo("play_pressed")); ADD_SIGNAL(MethodInfo("pause_pressed")); @@ -4741,6 +5046,7 @@ void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_err EditorNode::EditorNode() { + Input::get_singleton()->set_use_accumulated_input(true); Resource::_get_local_scene_func = _resource_get_edited_scene; VisualServer::get_singleton()->textures_keep_original(true); @@ -4851,6 +5157,10 @@ EditorNode::EditorNode() { import_image.instance(); ResourceFormatImporter::get_singleton()->add_importer(import_image); + Ref<ResourceImporterTextureAtlas> import_texture_atlas; + import_texture_atlas.instance(); + ResourceFormatImporter::get_singleton()->add_importer(import_texture_atlas); + Ref<ResourceImporterCSVTranslation> import_csv_translation; import_csv_translation.instance(); ResourceFormatImporter::get_singleton()->add_importer(import_csv_translation); @@ -4872,9 +5182,9 @@ EditorNode::EditorNode() { import_collada.instance(); import_scene->add_importer(import_collada); - Ref<EditorOBJImporter> import_obj; - import_obj.instance(); - import_scene->add_importer(import_obj); + Ref<EditorOBJImporter> import_obj2; + import_obj2.instance(); + import_scene->add_importer(import_obj2); Ref<EditorSceneImporterGLTF> import_gltf; import_gltf.instance(); @@ -4947,7 +5257,7 @@ EditorNode::EditorNode() { EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false); EDITOR_DEF("interface/inspector/horizontal_vector_types_editing", true); EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true); - EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial,Script"); + EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "SpatialMaterial,Script,MeshLibrary,TileSet"); EDITOR_DEF("run/auto_save/save_before_running", true); theme_base = memnew(Control); @@ -4976,7 +5286,7 @@ EditorNode::EditorNode() { main_vbox = memnew(VBoxContainer); gui_base->add_child(main_vbox); main_vbox->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8); - main_vbox->set_margin(MARGIN_TOP, 5 * EDSCALE); + main_vbox->add_constant_override("separation", 8 * EDSCALE); menu_hb = memnew(HBoxContainer); main_vbox->add_child(menu_hb); @@ -5188,11 +5498,8 @@ EditorNode::EditorNode() { viewport->add_constant_override("separation", 0); scene_root_parent->add_child(viewport); - PanelContainer *top_region = memnew(PanelContainer); - top_region->add_style_override("panel", gui_base->get_stylebox("MenuPanel", "EditorStyles")); HBoxContainer *left_menu_hb = memnew(HBoxContainer); - top_region->add_child(left_menu_hb); - menu_hb->add_child(top_region); + menu_hb->add_child(left_menu_hb); file_menu = memnew(MenuButton); file_menu->set_flat(false); @@ -5235,8 +5542,11 @@ EditorNode::EditorNode() { export_template_manager = memnew(ExportTemplateManager); gui_base->add_child(export_template_manager); + feature_profile_manager = memnew(EditorFeatureProfileManager); + gui_base->add_child(feature_profile_manager); about = memnew(EditorAbout); gui_base->add_child(about); + feature_profile_manager->connect("current_feature_profile_changed", this, "_feature_profile_changed"); warning = memnew(AcceptDialog); gui_base->add_child(warning); @@ -5276,7 +5586,7 @@ EditorNode::EditorNode() { p->add_shortcut(ED_SHORTCUT("editor/undo", TTR("Undo"), KEY_MASK_CMD + KEY_Z), EDIT_UNDO, true); p->add_shortcut(ED_SHORTCUT("editor/redo", TTR("Redo"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_Z), EDIT_REDO, true); p->add_separator(); - p->add_item(TTR("Revert Scene"), EDIT_REVERT); + p->add_shortcut(ED_SHORTCUT("editor/revert_scene", TTR("Revert Scene")), EDIT_REVERT); recent_scenes = memnew(PopupMenu); recent_scenes->set_name("RecentScenes"); @@ -5296,10 +5606,10 @@ EditorNode::EditorNode() { p = project_menu->get_popup(); p->set_hide_on_window_lose_focus(true); - p->add_item(TTR("Project Settings"), RUN_SETTINGS); + p->add_shortcut(ED_SHORTCUT("editor/project_settings", TTR("Project Settings")), RUN_SETTINGS); p->add_separator(); p->connect("id_pressed", this, "_menu_option"); - p->add_item(TTR("Export"), FILE_EXPORT_PROJECT); + p->add_shortcut(ED_SHORTCUT("editor/export", TTR("Export")), FILE_EXPORT_PROJECT); plugin_config_dialog = memnew(PluginConfigDialog); plugin_config_dialog->connect("plugin_ready", this, "_on_plugin_ready"); @@ -5310,10 +5620,10 @@ EditorNode::EditorNode() { tool_menu->connect("index_pressed", this, "_tool_menu_option"); p->add_child(tool_menu); p->add_submenu_item(TTR("Tools"), "Tools"); - tool_menu->add_item(TTR("Orphan Resource Explorer"), TOOLS_ORPHAN_RESOURCES); + tool_menu->add_shortcut(ED_SHORTCUT("editor/orphan_resource_explorer", TTR("Orphan Resource Explorer")), TOOLS_ORPHAN_RESOURCES); p->add_separator(); - p->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER); + p->add_shortcut(ED_SHORTCUT("editor/open_project_data_folder", TTR("Open Project Data Folder")), RUN_PROJECT_DATA_FOLDER); p->add_separator(); #ifdef OSX_ENABLED @@ -5322,11 +5632,10 @@ EditorNode::EditorNode() { p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_Q); #endif - PanelContainer *editor_region = memnew(PanelContainer); - main_editor_button_vb = memnew(HBoxContainer); - editor_region->add_child(main_editor_button_vb); menu_hb->add_spacer(); - menu_hb->add_child(editor_region); + + main_editor_button_vb = memnew(HBoxContainer); + menu_hb->add_child(main_editor_button_vb); debug_menu = memnew(MenuButton); debug_menu->set_flat(false); @@ -5338,21 +5647,21 @@ EditorNode::EditorNode() { p = debug_menu->get_popup(); p->set_hide_on_window_lose_focus(true); p->set_hide_on_item_selection(false); - p->add_check_item(TTR("Deploy with Remote Debug"), RUN_DEPLOY_REMOTE_DEBUG); + p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG); p->set_item_tooltip(p->get_item_count() - 1, TTR("When exporting or deploying, the resulting executable will attempt to connect to the IP of this computer in order to be debugged.")); - p->add_check_item(TTR("Small Deploy with Network FS"), RUN_FILE_SERVER); + p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network FS")), RUN_FILE_SERVER); p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is enabled, export or deploy will produce a minimal executable.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploy will use the USB cable for faster performance. This option speeds up testing for games with a large footprint.")); p->add_separator(); - p->add_check_item(TTR("Visible Collision Shapes"), RUN_DEBUG_COLLISONS); + p->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS); p->set_item_tooltip(p->get_item_count() - 1, TTR("Collision shapes and raycast nodes (for 2D and 3D) will be visible on the running game if this option is turned on.")); - p->add_check_item(TTR("Visible Navigation"), RUN_DEBUG_NAVIGATION); + p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION); p->set_item_tooltip(p->get_item_count() - 1, TTR("Navigation meshes and polygons will be visible on the running game if this option is turned on.")); p->add_separator(); //those are now on by default, since they are harmless - p->add_check_item(TTR("Sync Scene Changes"), RUN_LIVE_DEBUG); + p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Sync Scene Changes")), RUN_LIVE_DEBUG); p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any changes made to the scene in the editor will be replicated in the running game.\nWhen used remotely on a device, this is more efficient with network filesystem.")); p->set_item_checked(p->get_item_count() - 1, true); - p->add_check_item(TTR("Sync Script Changes"), RUN_RELOAD_SCRIPTS); + p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Sync Script Changes")), RUN_RELOAD_SCRIPTS); p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any script that is saved will be reloaded on the running game.\nWhen used remotely on a device, this is more efficient with network filesystem.")); p->set_item_checked(p->get_item_count() - 1, true); p->connect("id_pressed", this, "_menu_option"); @@ -5368,7 +5677,7 @@ EditorNode::EditorNode() { p = settings_menu->get_popup(); p->set_hide_on_window_lose_focus(true); - p->add_item(TTR("Editor Settings"), SETTINGS_PREFERENCES); + p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings")), SETTINGS_PREFERENCES); p->add_separator(); editor_layouts = memnew(PopupMenu); @@ -5393,6 +5702,10 @@ EditorNode::EditorNode() { } p->add_separator(); + p->add_item(TTR("Manage Editor Features"), SETTINGS_MANAGE_FEATURE_PROFILES); + + p->add_separator(); + p->add_item(TTR("Manage Export Templates"), SETTINGS_MANAGE_EXPORT_TEMPLATES); // Help Menu @@ -5406,20 +5719,17 @@ EditorNode::EditorNode() { p = help_menu->get_popup(); p->set_hide_on_window_lose_focus(true); p->connect("id_pressed", this, "_menu_option"); - p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_F4), HELP_SEARCH); + p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_MASK_SHIFT | KEY_F1), HELP_SEARCH); p->add_separator(); - p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Online Docs"), HELP_DOCS); - p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Q&A"), HELP_QA); - p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Issue Tracker"), HELP_ISSUES); - p->add_icon_item(gui_base->get_icon("Instance", "EditorIcons"), TTR("Community"), HELP_COMMUNITY); + p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Docs")), HELP_DOCS); + p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Q&A")), HELP_QA); + p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/issue_tracker", TTR("Issue Tracker")), HELP_ISSUES); + p->add_icon_shortcut(gui_base->get_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/community", TTR("Community")), HELP_COMMUNITY); p->add_separator(); - p->add_icon_item(gui_base->get_icon("Godot", "EditorIcons"), TTR("About"), HELP_ABOUT); - - play_button_panel = memnew(PanelContainer); - menu_hb->add_child(play_button_panel); + p->add_icon_shortcut(gui_base->get_icon("Godot", "EditorIcons"), ED_SHORTCUT("editor/about", TTR("About")), HELP_ABOUT); HBoxContainer *play_hb = memnew(HBoxContainer); - play_button_panel->add_child(play_hb); + menu_hb->add_child(play_hb); play_button = memnew(ToolButton); play_hb->add_child(play_button); @@ -5497,7 +5807,6 @@ EditorNode::EditorNode() { video_driver = memnew(OptionButton); video_driver->set_flat(true); video_driver->set_focus_mode(Control::FOCUS_NONE); - video_driver->set_v_size_flags(Control::SIZE_SHRINK_CENTER); video_driver->connect("item_selected", this, "_video_driver_selected"); video_driver->add_font_override("font", gui_base->get_font("bold", "EditorFonts")); right_menu_hb->add_child(video_driver); @@ -5533,7 +5842,7 @@ EditorNode::EditorNode() { layout_dialog->connect("name_confirmed", this, "_dialog_action"); update_menu = memnew(MenuButton); - update_menu->set_tooltip(TTR("Spins when the editor window repaints!")); + update_menu->set_tooltip(TTR("Spins when the editor window redraws.")); right_menu_hb->add_child(update_menu); update_menu->set_icon(gui_base->get_icon("Progress1", "EditorIcons")); update_menu->get_popup()->connect("id_pressed", this, "_menu_option"); @@ -5557,9 +5866,9 @@ EditorNode::EditorNode() { node_dock = memnew(NodeDock); filesystem_dock = memnew(FileSystemDock(this)); - filesystem_dock->set_file_list_display_mode(int(EditorSettings::get_singleton()->get("docks/filesystem/files_display_mode"))); filesystem_dock->connect("open", this, "open_request"); filesystem_dock->connect("instance", this, "_instance_request"); + filesystem_dock->connect("display_mode_changed", this, "_save_docks"); // Scene: Top left dock_slot[DOCK_SLOT_LEFT_UR]->add_child(scene_tree_dock); @@ -5624,7 +5933,7 @@ EditorNode::EditorNode() { bottom_panel->add_child(bottom_panel_vb); bottom_panel_hb = memnew(HBoxContainer); - bottom_panel_hb->set_custom_minimum_size(Size2(0, 24)); // Adjust for the height of the "Expand Bottom Dock" icon. + bottom_panel_hb->set_custom_minimum_size(Size2(0, 24 * EDSCALE)); // Adjust for the height of the "Expand Bottom Dock" icon. bottom_panel_vb->add_child(bottom_panel_hb); bottom_panel_hb_editors = memnew(HBoxContainer); @@ -5758,6 +6067,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(SpriteEditorPlugin(this))); add_editor_plugin(memnew(Skeleton2DEditorPlugin(this))); add_editor_plugin(memnew(ParticlesEditorPlugin(this))); + add_editor_plugin(memnew(CPUParticles2DEditorPlugin(this))); add_editor_plugin(memnew(CPUParticlesEditorPlugin(this))); add_editor_plugin(memnew(ResourcePreloaderEditorPlugin(this))); add_editor_plugin(memnew(ItemListEditorPlugin(this))); @@ -5786,6 +6096,8 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(SkeletonEditorPlugin(this))); add_editor_plugin(memnew(SkeletonIKEditorPlugin(this))); add_editor_plugin(memnew(PhysicalBonePlugin(this))); + add_editor_plugin(memnew(MeshEditorPlugin(this))); + add_editor_plugin(memnew(MaterialEditorPlugin(this))); for (int i = 0; i < EditorPlugins::get_plugin_count(); i++) add_editor_plugin(EditorPlugins::create(i, this)); @@ -6037,6 +6349,10 @@ void EditorPluginList::add_plugin(EditorPlugin *p_plugin) { plugins_list.push_back(p_plugin); } +void EditorPluginList::remove_plugin(EditorPlugin *p_plugin) { + plugins_list.erase(p_plugin); +} + bool EditorPluginList::empty() { return plugins_list.empty(); } |