diff options
Diffstat (limited to 'editor/editor_node.cpp')
-rw-r--r-- | editor/editor_node.cpp | 414 |
1 files changed, 365 insertions, 49 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 6140412a32..8703076a57 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -47,6 +47,7 @@ #include "core/translation.h" #include "core/version.h" #include "main/input_default.h" +#include "main/main.h" #include "scene/resources/packed_scene.h" #include "servers/physics_2d_server.h" @@ -65,6 +66,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 +83,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" @@ -305,7 +308,14 @@ 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(); /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ @@ -557,11 +567,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); } @@ -569,11 +582,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); } @@ -910,7 +926,8 @@ bool EditorNode::_find_and_save_edited_subresources(Object *obj, Map<RES, bool> ret_changed = true; } } break; - default: {} + default: { + } } } @@ -1291,6 +1308,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(); @@ -1439,17 +1457,48 @@ 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); } @@ -1582,7 +1631,7 @@ void EditorNode::_edit_current() { editable_warning = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); } else { if ((!get_edited_scene() || get_edited_scene()->get_filename() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") { - editable_warning = TTR("This resource belongs to a scene that was instanced or inherited.\nChanges to it will not be kept when saving the current scene."); + editable_warning = TTR("This resource belongs to a scene that was instanced or inherited.\nChanges to it won't be kept when saving the current scene."); } } } else if (current_res->get_path().is_resource_file()) { @@ -1607,14 +1656,14 @@ void EditorNode::_edit_current() { if (get_edited_scene() && get_edited_scene()->get_filename() != String()) { String source_scene = get_edited_scene()->get_filename(); if (FileAccess::exists(source_scene + ".import")) { - editable_warning = TTR("This scene was imported, so changes to it will not be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); + editable_warning = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); } } } else { if (current_obj->is_class("ScriptEditorDebuggerInspectedObject")) { - editable_warning = TTR("This is a remote object so changes to it will not be kept.\nPlease read the documentation relevant to debugging to better understand this workflow."); + editable_warning = TTR("This is a remote object, so changes to it won't be kept.\nPlease read the documentation relevant to debugging to better understand this workflow."); capitalize = false; disable_folding = true; } @@ -1639,6 +1688,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 @@ -1676,7 +1731,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); @@ -1684,7 +1743,6 @@ 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(); @@ -1879,6 +1937,21 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { open_request(previous_scenes.back()->get()); } break; + case FILE_CLOSE_OTHERS: + case FILE_CLOSE_RIGHT: + case FILE_CLOSE_ALL: { + if (editor_data.get_edited_scene_count() > 1 && (current_option != FILE_CLOSE_RIGHT || editor_data.get_edited_scene() < editor_data.get_edited_scene_count() - 1)) { + int next_tab = editor_data.get_edited_scene() + 1; + next_tab %= editor_data.get_edited_scene_count(); + _scene_tab_closed(next_tab, current_option); + } else { + if (current_option != FILE_CLOSE_ALL) + current_option = -1; + else + _scene_tab_closed(editor_data.get_edited_scene()); + } + + } break; case FILE_CLOSE_ALL_AND_QUIT: case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER: case FILE_CLOSE: { @@ -1899,7 +1972,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { break; } - } // fallthrough + FALLTHROUGH; + } case SCENE_TAB_CLOSE: case FILE_SAVE_SCENE: { @@ -1915,11 +1989,12 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (scene_idx != -1) _discard_changes(); + save_layout(); 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; @@ -2212,6 +2287,23 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir()); } break; + case FILE_INSTALL_ANDROID_SOURCE: { + + if (p_confirmed) { + export_template_manager->install_android_template(); + } else { + if (DirAccess::exists("res://android/build")) { + remove_android_build_template->popup_centered_minsize(); + } else if (export_template_manager->can_install_android_template()) { + install_android_build_template->popup_centered_minsize(); + } else { + custom_build_manage_templates->popup_centered_minsize(); + } + } + } break; + case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: { + OS::get_singleton()->shell_open(String("file://") + ProjectSettings::get_singleton()->get_resource_path().plus_file("android")); + } break; case FILE_QUIT: case RUN_PROJECT_MANAGER: { @@ -2357,6 +2449,17 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { export_template_manager->popup_manager(); } break; + case SETTINGS_MANAGE_FEATURE_PROFILES: { + + Size2 popup_size = Size2(900, 800) * editor_get_scale(); + Size2 window_size = get_viewport()->get_size(); + + popup_size.x = MIN(window_size.x * 0.8, popup_size.x); + popup_size.y = MIN(window_size.y * 0.8, popup_size.y); + + feature_profile_manager->popup_centered(popup_size); + + } break; case SETTINGS_TOGGLE_FULLSCREEN: { OS::get_singleton()->set_window_fullscreen(!OS::get_singleton()->is_window_fullscreen()); @@ -2460,6 +2563,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) { void EditorNode::_exit_editor() { exiting = true; resource_preview->stop(); //stop early to avoid crashes + _save_docks(); get_tree()->quit(); } @@ -2470,6 +2574,9 @@ void EditorNode::_discard_changes(const String &p_str) { case FILE_CLOSE_ALL_AND_QUIT: case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER: case FILE_CLOSE: + case FILE_CLOSE_OTHERS: + case FILE_CLOSE_RIGHT: + case FILE_CLOSE_ALL: case SCENE_TAB_CLOSE: { _remove_scene(tab_closing); @@ -2482,6 +2589,15 @@ void EditorNode::_discard_changes(const String &p_str) { } else { _menu_option_confirm(current_option, false); } + } else if (current_option == FILE_CLOSE_OTHERS || current_option == FILE_CLOSE_RIGHT) { + if (editor_data.get_edited_scene_count() == 1 || (current_option == FILE_CLOSE_RIGHT && editor_data.get_edited_scene_count() <= editor_data.get_edited_scene() + 1)) { + current_option = -1; + save_confirmation->hide(); + } else { + _menu_option_confirm(current_option, false); + } + } else if (current_option == FILE_CLOSE_ALL && editor_data.get_edited_scene_count() > 0) { + _menu_option_confirm(current_option, false); } else { current_option = -1; save_confirmation->hide(); @@ -2539,10 +2655,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); } @@ -3282,6 +3401,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>(); @@ -3350,12 +3470,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; + } + + 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_valid()) { - icon = gui_base->get_icon(ScriptServer::get_global_class_native_base(p_class), "EditorIcons"); + + if (icon.is_null()) { + icon = gui_base->get_icon(ScriptServer::get_global_class_base(p_class), "EditorIcons"); } + return icon; } @@ -3801,7 +3939,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(); @@ -3980,6 +4124,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; } @@ -4080,8 +4225,8 @@ void EditorNode::_scene_tab_script_edited(int p_tab) { inspector_dock->edit_resource(script); } -void EditorNode::_scene_tab_closed(int p_tab) { - current_option = SCENE_TAB_CLOSE; +void EditorNode::_scene_tab_closed(int p_tab, int option) { + current_option = option; tab_closing = p_tab; Node *scene = editor_data.get_edited_scene_root(p_tab); if (!scene) { @@ -4154,7 +4299,11 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) { scene_tabs_context_menu->add_separator(); scene_tabs_context_menu->add_item(TTR("Show in FileSystem"), FILE_SHOW_IN_FILESYSTEM); scene_tabs_context_menu->add_item(TTR("Play This Scene"), RUN_PLAY_SCENE); + scene_tabs_context_menu->add_separator(); scene_tabs_context_menu->add_item(TTR("Close Tab"), FILE_CLOSE); + scene_tabs_context_menu->add_item(TTR("Close Other Tabs"), FILE_CLOSE_OTHERS); + scene_tabs_context_menu->add_item(TTR("Close Tabs to the Right"), FILE_CLOSE_RIGHT); + scene_tabs_context_menu->add_item(TTR("Close All Tabs"), FILE_CLOSE_ALL); } scene_tabs_context_menu->set_position(mb->get_global_position()); scene_tabs_context_menu->popup(); @@ -4537,19 +4686,53 @@ 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_selected_path()); - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + _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) { @@ -4786,6 +4969,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); @@ -4864,6 +5080,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")); @@ -4883,6 +5100,68 @@ void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_err en->log->add_message(p_string, p_error ? EditorLog::MSG_TYPE_ERROR : EditorLog::MSG_TYPE_STD); } +static void _execute_thread(void *p_ud) { + + EditorNode::ExecuteThreadArgs *eta = (EditorNode::ExecuteThreadArgs *)p_ud; + Error err = OS::get_singleton()->execute(eta->path, eta->args, true, NULL, &eta->output, &eta->exitcode, true, eta->execute_output_mutex); + print_verbose("Thread exit status: " + itos(eta->exitcode)); + if (err != OK) { + eta->exitcode = err; + } + + eta->done = true; +} + +int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors) { + + execute_output_dialog->set_title(p_title); + execute_output_dialog->get_ok()->set_disabled(true); + execute_outputs->clear(); + execute_outputs->set_scroll_follow(true); + execute_output_dialog->popup_centered_ratio(); + + ExecuteThreadArgs eta; + eta.path = p_path; + eta.args = p_arguments; + eta.execute_output_mutex = Mutex::create(); + eta.exitcode = 255; + eta.done = false; + + int prev_len = 0; + + eta.execute_output_thread = Thread::create(_execute_thread, &eta); + + ERR_FAIL_COND_V(!eta.execute_output_thread, 0); + + while (!eta.done) { + eta.execute_output_mutex->lock(); + if (prev_len != eta.output.length()) { + String to_add = eta.output.substr(prev_len, eta.output.length()); + prev_len = eta.output.length(); + execute_outputs->add_text(to_add); + Main::iteration(); + } + eta.execute_output_mutex->unlock(); + OS::get_singleton()->delay_usec(1000); + } + + Thread::wait_to_finish(eta.execute_output_thread); + memdelete(eta.execute_output_thread); + memdelete(eta.execute_output_mutex); + execute_outputs->add_text("\nExit Code: " + itos(eta.exitcode)); + + if (p_close_on_errors && eta.exitcode != 0) { + execute_output_dialog->hide(); + } + if (p_close_on_ok && eta.exitcode == 0) { + execute_output_dialog->hide(); + } + + execute_output_dialog->get_ok()->set_disabled(false); + + return eta.exitcode; +} + EditorNode::EditorNode() { Input::get_singleton()->set_use_accumulated_input(true); @@ -4996,6 +5275,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); @@ -5277,7 +5560,7 @@ EditorNode::EditorNode() { scene_tabs->set_drag_to_rearrange_enabled(true); scene_tabs->connect("tab_changed", this, "_scene_tab_changed"); scene_tabs->connect("right_button_pressed", this, "_scene_tab_script_edited"); - scene_tabs->connect("tab_close", this, "_scene_tab_closed"); + scene_tabs->connect("tab_close", this, "_scene_tab_closed", varray(SCENE_TAB_CLOSE)); scene_tabs->connect("tab_hover", this, "_scene_tab_hover"); scene_tabs->connect("mouse_exited", this, "_scene_tab_exit"); scene_tabs->connect("gui_input", this, "_scene_tab_input"); @@ -5377,8 +5660,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); @@ -5418,7 +5704,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"); @@ -5438,10 +5724,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"); @@ -5450,12 +5736,13 @@ EditorNode::EditorNode() { tool_menu = memnew(PopupMenu); tool_menu->set_name("Tools"); tool_menu->connect("index_pressed", this, "_tool_menu_option"); + p->add_separator(); 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_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER); p->add_separator(); - - p->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER); + p->add_item(TTR("Install Android Build Template"), FILE_INSTALL_ANDROID_SOURCE); p->add_separator(); #ifdef OSX_ENABLED @@ -5479,21 +5766,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"); @@ -5509,7 +5796,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); @@ -5534,6 +5821,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 @@ -5547,14 +5838,14 @@ 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); + p->add_icon_shortcut(gui_base->get_icon("Godot", "EditorIcons"), ED_SHORTCUT("editor/about", TTR("About")), HELP_ABOUT); HBoxContainer *play_hb = memnew(HBoxContainer); menu_hb->add_child(play_hb); @@ -5798,6 +6089,24 @@ EditorNode::EditorNode() { save_confirmation->connect("confirmed", this, "_menu_confirm_current"); save_confirmation->connect("custom_action", this, "_discard_changes"); + custom_build_manage_templates = memnew(ConfirmationDialog); + custom_build_manage_templates->set_text(TTR("Android build template is missing, please install relevant templates.")); + custom_build_manage_templates->get_ok()->set_text(TTR("Manage Templates")); + custom_build_manage_templates->connect("confirmed", this, "_menu_option", varray(SETTINGS_MANAGE_EXPORT_TEMPLATES)); + gui_base->add_child(custom_build_manage_templates); + + install_android_build_template = memnew(ConfirmationDialog); + install_android_build_template->set_text(TTR("This will install the Android project for custom builds.\nNote that, in order to use it, it needs to be enabled per export preset.")); + install_android_build_template->get_ok()->set_text(TTR("Install")); + install_android_build_template->connect("confirmed", this, "_menu_confirm_current"); + gui_base->add_child(install_android_build_template); + + remove_android_build_template = memnew(ConfirmationDialog); + remove_android_build_template->set_text(TTR("Android build template is already installed and it won't be overwritten.\nRemove the \"build\" directory manually before attempting this operation again.")); + remove_android_build_template->get_ok()->set_text(TTR("Show in File Manager")); + remove_android_build_template->connect("confirmed", this, "_menu_option", varray(FILE_EXPLORE_ANDROID_BUILD_TEMPLATES)); + gui_base->add_child(remove_android_build_template); + file_templates = memnew(EditorFileDialog); file_templates->set_title(TTR("Import Templates From ZIP File")); @@ -5895,6 +6204,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))); @@ -6011,6 +6321,12 @@ EditorNode::EditorNode() { load_error_dialog->set_title(TTR("Load Errors")); gui_base->add_child(load_error_dialog); + execute_outputs = memnew(RichTextLabel); + execute_output_dialog = memnew(AcceptDialog); + execute_output_dialog->add_child(execute_outputs); + execute_output_dialog->set_title(TTR("")); + gui_base->add_child(execute_output_dialog); + EditorFileSystem::get_singleton()->connect("sources_changed", this, "_sources_changed"); EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_fs_changed"); EditorFileSystem::get_singleton()->connect("resources_reimported", this, "_resources_reimported"); |