diff options
Diffstat (limited to 'editor/editor_node.cpp')
-rw-r--r-- | editor/editor_node.cpp | 426 |
1 files changed, 216 insertions, 210 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index e7946f56da..362159cb56 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -54,6 +54,7 @@ #include "scene/gui/dialogs.h" #include "scene/gui/file_dialog.h" #include "scene/gui/link_button.h" +#include "scene/gui/menu_bar.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" #include "scene/gui/panel_container.h" @@ -104,6 +105,7 @@ #include "editor/editor_themes.h" #include "editor/editor_toaster.h" #include "editor/editor_translation_parser.h" +#include "editor/editor_undo_redo_manager.h" #include "editor/export/editor_export.h" #include "editor/export/export_template_manager.h" #include "editor/export/project_export.h" @@ -348,8 +350,7 @@ void EditorNode::_update_scene_tabs() { icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node"); } - int current = editor_data.get_edited_scene(); - bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon); if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) { @@ -596,15 +597,15 @@ void EditorNode::_notification(int p_what) { opening_prev = false; } - bool unsaved_cache_changed = false; - if (unsaved_cache != (saved_version != editor_data.get_undo_redo().get_version())) { - unsaved_cache = (saved_version != editor_data.get_undo_redo().get_version()); - unsaved_cache_changed = true; + bool global_unsaved = get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY); + bool scene_or_global_unsaved = global_unsaved || get_undo_redo()->is_history_unsaved(editor_data.get_current_edited_scene_history_id()); + if (unsaved_cache != scene_or_global_unsaved) { + unsaved_cache = scene_or_global_unsaved; + _update_title(); } - if (last_checked_version != editor_data.get_undo_redo().get_version()) { + if (editor_data.is_scene_changed(-1)) { _update_scene_tabs(); - last_checked_version = editor_data.get_undo_redo().get_version(); } // Update the animation frame of the update spinner. @@ -630,7 +631,7 @@ void EditorNode::_notification(int p_what) { ResourceImporterTexture::get_singleton()->update_imports(); - if (settings_changed || unsaved_cache_changed) { + if (settings_changed) { _update_title(); } @@ -660,6 +661,7 @@ void EditorNode::_notification(int p_what) { command_palette->register_shortcuts_as_command(); + MessageQueue::get_singleton()->push_callable(callable_mp(this, &EditorNode::_begin_first_scan)); /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } break; @@ -751,11 +753,7 @@ void EditorNode::_notification(int p_what) { scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles"))); scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox(SNAME("SceneTabBG"), SNAME("EditorStyles"))); - file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - debug_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - settings_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - help_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); + main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); } scene_tabs->set_max_tab_width(int(EDITOR_GET("interface/scene_tabs/maximum_width")) * EDSCALE); @@ -803,16 +801,15 @@ void EditorNode::_notification(int p_what) { dock_tab_move_right->set_icon(theme->get_icon(SNAME("Forward"), SNAME("EditorIcons"))); } - PopupMenu *p = help_menu->get_popup(); - p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons"))); - p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); - p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); - p->set_item_icon(p->get_item_index(HELP_REPORT_A_BUG), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); - p->set_item_icon(p->get_item_index(HELP_SUGGEST_A_FEATURE), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); - p->set_item_icon(p->get_item_index(HELP_SEND_DOCS_FEEDBACK), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); - p->set_item_icon(p->get_item_index(HELP_COMMUNITY), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); - p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons"))); - p->set_item_icon(p->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_DOCS), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_QA), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_REPORT_A_BUG), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_SUGGEST_A_FEATURE), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_SEND_DOCS_FEEDBACK), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_COMMUNITY), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_ABOUT), gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons"))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons"))); for (int i = 0; i < main_editor_buttons.size(); i++) { main_editor_buttons.write[i]->add_theme_font_override("font", gui_base->get_theme_font(SNAME("main_button_font"), SNAME("EditorFonts"))); @@ -1047,6 +1044,8 @@ void EditorNode::_sources_changed(bool p_exist) { if (waiting_for_first_scan) { waiting_for_first_scan = false; + Engine::get_singleton()->startup_benchmark_end_measure(); // editor_scan_and_reimport + // Reload the global shader variables, but this time // loading textures, as they are now properly imported. RenderingServer::get_singleton()->global_shader_uniforms_load_settings(true); @@ -1059,8 +1058,16 @@ void EditorNode::_sources_changed(bool p_exist) { _load_docks(); if (!defer_load_scene.is_empty()) { + Engine::get_singleton()->startup_benchmark_begin_measure("editor_load_scene"); load_scene(defer_load_scene); defer_load_scene = ""; + Engine::get_singleton()->startup_benchmark_end_measure(); + + if (use_startup_benchmark) { + Engine::get_singleton()->startup_dump(startup_benchmark_file); + startup_benchmark_file = String(); + use_startup_benchmark = false; + } } } } @@ -1131,7 +1138,6 @@ void EditorNode::_reload_modified_scenes() { } } - get_undo_redo()->clear_history(false); set_current_scene(current_idx); _update_scene_tabs(); disk_changed->hide(); @@ -1685,6 +1691,8 @@ int EditorNode::_save_external_resources() { saved++; } + get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY); + return saved; } @@ -1766,11 +1774,7 @@ void EditorNode::_save_scene(String p_file, int idx) { if (err == OK) { scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_file)); - if (idx < 0 || idx == editor_data.get_edited_scene()) { - set_current_version(editor_data.get_undo_redo().get_version()); - } else { - editor_data.set_edited_scene_version(0, idx); - } + editor_data.set_scene_as_saved(idx); editor_data.set_scene_modified_time(idx, FileAccess::get_modified_time(p_file)); editor_folding.save_scene_folding(scene, p_file); @@ -1815,15 +1819,15 @@ void EditorNode::restart_editor() { List<String> args; + for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) { + args.push_back(a); + } + args.push_back("--path"); args.push_back(ProjectSettings::get_singleton()->get_resource_path()); args.push_back("-e"); - if (OS::get_singleton()->is_disable_crash_handler()) { - args.push_back("--disable-crash-handler"); - } - if (!to_reopen.is_empty()) { args.push_back(to_reopen); } @@ -1862,12 +1866,9 @@ void EditorNode::_mark_unsaved_scenes() { } String path = node->get_scene_file_path(); - if (!(path.is_empty() || FileAccess::exists(path))) { - if (i == editor_data.get_edited_scene()) { - set_current_version(-1); - } else { - editor_data.set_edited_scene_version(-1, i); - } + if (!path.is_empty() && !FileAccess::exists(path)) { + // Mark scene tab as unsaved if the file is gone. + get_undo_redo()->set_history_as_unsaved(editor_data.get_scene_history_id(i)); } } @@ -1942,6 +1943,21 @@ void EditorNode::_dialog_action(String p_file) { } } break; + case FILE_SAVE_AND_RUN_MAIN_SCENE: { + ProjectSettings::get_singleton()->set("application/run/main_scene", p_file); + ProjectSettings::get_singleton()->save(); + + if (file->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) { + _save_default_environment(); + _save_scene_with_preview(p_file); + if ((bool)pick_main_scene->get_meta("from_native", false)) { + run_native->resume_run_native(); + } else { + _run(false, p_file); + } + } + } break; + case FILE_EXPORT_MESH_LIBRARY: { Ref<MeshLibrary> ml; if (file_export_lib_merge->is_pressed() && FileAccess::exists(p_file)) { @@ -2396,10 +2412,8 @@ void EditorNode::_run(bool p_current, const String &p_custom) { } if (scene->get_scene_file_path().is_empty()) { - current_menu_option = -1; - _menu_option(FILE_SAVE_AS_SCENE); - // Set the option to save and run so when the dialog is accepted, the scene runs. current_menu_option = FILE_SAVE_AND_RUN; + _menu_option_confirm(FILE_SAVE_AS_SCENE, true); file->set_title(TTR("Save scene before running...")); return; } @@ -2414,6 +2428,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { if (!ensure_main_scene(false)) { return; } + run_filename = GLOBAL_DEF_BASIC("application/run/main_scene", ""); } if (bool(EDITOR_GET("run/auto_save/save_before_running"))) { @@ -2711,9 +2726,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) { log->add_message(TTR("Can't undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR); } else { - String action = editor_data.get_undo_redo().get_current_action_name(); + String action = editor_data.get_undo_redo()->get_current_action_name(); - if (!editor_data.get_undo_redo().undo()) { + if (!editor_data.get_undo_redo()->undo()) { log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR); } else if (!action.is_empty()) { log->add_message(vformat(TTR("Undo: %s"), action), EditorLog::MSG_TYPE_EDITOR); @@ -2724,10 +2739,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) { log->add_message(TTR("Can't redo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR); } else { - if (!editor_data.get_undo_redo().redo()) { + if (!editor_data.get_undo_redo()->redo()) { log->add_message(TTR("Nothing to redo."), EditorLog::MSG_TYPE_EDITOR); } else { - String action = editor_data.get_undo_redo().get_current_action_name(); + String action = editor_data.get_undo_redo()->get_current_action_name(); log->add_message(vformat(TTR("Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR); } } @@ -2762,7 +2777,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { ERR_PRINT("Failed to load scene"); } editor_data.move_edited_scene_to_index(cur_idx); - get_undo_redo()->clear_history(false); + get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id()); scene_tabs->set_current_tab(cur_idx); } break; @@ -3075,8 +3090,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) { if (!editor_data.get_edited_scene_root(i)) { continue; } - int current = editor_data.get_edited_scene(); - bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i)); if (unsaved) { String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path(); if (p_valid_filename && scene_filename.length() == 0) { @@ -3162,6 +3176,9 @@ void EditorNode::_discard_changes(const String &p_str) { String exec = OS::get_singleton()->get_executable_path(); List<String> args; + for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) { + args.push_back(a); + } args.push_back("--path"); args.push_back(exec.get_base_dir()); args.push_back("--project-manager"); @@ -3181,17 +3198,15 @@ void EditorNode::_update_file_menu_opened() { Ref<Shortcut> reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene"); reopen_closed_scene_sc->set_name(TTR("Reopen Closed Scene")); - PopupMenu *pop = file_menu->get_popup(); - pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty()); + file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty()); - const UndoRedo &undo_redo = editor_data.get_undo_redo(); - pop->set_item_disabled(pop->get_item_index(EDIT_UNDO), !undo_redo.has_undo()); - pop->set_item_disabled(pop->get_item_index(EDIT_REDO), !undo_redo.has_redo()); + Ref<EditorUndoRedoManager> undo_redo = editor_data.get_undo_redo(); + file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo->has_undo()); + file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo->has_redo()); } void EditorNode::_update_file_menu_closed() { - PopupMenu *pop = file_menu->get_popup(); - pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), false); + file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), false); } Control *EditorNode::get_main_control() { @@ -3443,7 +3458,6 @@ void EditorNode::_remove_edited_scene(bool p_change_tab) { _scene_tab_changed(new_index); } editor_data.remove_scene(old_index); - editor_data.get_undo_redo().clear_history(false); _update_title(); _update_scene_tabs(); } @@ -3499,7 +3513,6 @@ Dictionary EditorNode::_get_main_scene_state() { state["main_tab"] = _get_current_main_editor(); state["scene_tree_offset"] = SceneTreeDock::get_singleton()->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_value(); state["property_edit_offset"] = InspectorDock::get_inspector_singleton()->get_scroll_offset(); - state["saved_version"] = saved_version; state["node_filter"] = SceneTreeDock::get_singleton()->get_filter(); return state; } @@ -3559,11 +3572,6 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) { editor_data.notify_edited_scene_changed(); } -void EditorNode::set_current_version(uint64_t p_version) { - saved_version = p_version; - editor_data.set_edited_scene_version(p_version); -} - bool EditorNode::is_changing_scene() const { return changing_scene; } @@ -3583,7 +3591,7 @@ void EditorNode::set_current_scene(int p_idx) { editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx)); } - call_deferred(SNAME("_clear_undo_history")); + get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(p_idx)); } changing_scene = true; @@ -3600,8 +3608,8 @@ void EditorNode::set_current_scene(int p_idx) { Node *new_scene = editor_data.get_edited_scene_root(); - if (Object::cast_to<Popup>(new_scene)) { - Object::cast_to<Popup>(new_scene)->show(); + if (Popup *p = Object::cast_to<Popup>(new_scene)) { + p->show(); } SceneTreeDock::get_singleton()->set_edited_scene(new_scene); @@ -3619,6 +3627,7 @@ void EditorNode::set_current_scene(int p_idx) { _edit_current(true); _update_title(); + _update_scene_tabs(); call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up. } @@ -3777,7 +3786,6 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b set_edited_scene(new_scene); _get_scene_metadata(p_scene); - saved_version = editor_data.get_undo_redo().get_version(); _update_title(); _update_scene_tabs(); _add_to_recent_scenes(lpath); @@ -3828,6 +3836,10 @@ void EditorNode::request_instantiate_scenes(const Vector<String> &p_files) { SceneTreeDock::get_singleton()->instantiate_scenes(p_files); } +Ref<EditorUndoRedoManager> &EditorNode::get_undo_redo() { + return singleton->editor_data.get_undo_redo(); +} + void EditorNode::_inherit_request(String p_file) { current_menu_option = FILE_NEW_INHERITED_SCENE; _dialog_action(p_file); @@ -3988,6 +4000,7 @@ void EditorNode::register_editor_types() { GDREGISTER_CLASS(EditorSpinSlider); GDREGISTER_CLASS(EditorResourcePicker); GDREGISTER_CLASS(EditorScriptPicker); + GDREGISTER_ABSTRACT_CLASS(EditorUndoRedoManager); GDREGISTER_ABSTRACT_CLASS(FileSystemDock); GDREGISTER_VIRTUAL_CLASS(EditorFileSystemImportFormatSupportQuery); @@ -4102,8 +4115,15 @@ void EditorNode::_pick_main_scene_custom_action(const String &p_custom_action_na } pick_main_scene->hide(); - current_menu_option = SETTINGS_PICK_MAIN_SCENE; - _dialog_action(scene->get_scene_file_path()); + + if (!FileAccess::exists(scene->get_scene_file_path())) { + current_menu_option = FILE_SAVE_AND_RUN_MAIN_SCENE; + _menu_option_confirm(FILE_SAVE_AS_SCENE, true); + file->set_title(TTR("Save scene before running...")); + } else { + current_menu_option = SETTINGS_PICK_MAIN_SCENE; + _dialog_action(scene->get_scene_file_path()); + } } } @@ -4303,6 +4323,15 @@ void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog) { Vector<EditorNodeInitCallback> EditorNode::_init_callbacks; +void EditorNode::_begin_first_scan() { + Engine::get_singleton()->startup_benchmark_begin_measure("editor_scan_and_import"); + EditorFileSystem::get_singleton()->scan(); +} +void EditorNode::set_use_startup_benchmark(bool p_use_startup_benchmark, const String &p_startup_benchmark_file) { + use_startup_benchmark = p_use_startup_benchmark; + startup_benchmark_file = p_startup_benchmark_file; +} + Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only) { export_defer.preset = p_preset; export_defer.path = p_path; @@ -5113,9 +5142,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) { return; } - bool unsaved = (p_tab == editor_data.get_edited_scene()) - ? saved_version != editor_data.get_undo_redo().get_version() - : editor_data.get_scene_version(p_tab) != 0; + bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(p_tab)); if (unsaved) { save_confirmation->set_ok_button_text(TTR("Save & Close")); save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene->get_scene_file_path().is_empty() ? scene->get_scene_file_path() : "unsaved scene")); @@ -5227,23 +5254,10 @@ void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_p void EditorNode::_scene_tab_changed(int p_tab) { tab_preview_panel->hide(); - bool unsaved = (saved_version != editor_data.get_undo_redo().get_version()); - if (p_tab == editor_data.get_edited_scene()) { return; // Pointless. } - - uint64_t next_scene_version = editor_data.get_scene_version(p_tab); - - editor_data.get_undo_redo().create_action(TTR("Switch Scene Tab")); - editor_data.get_undo_redo().add_do_method(this, "set_current_version", unsaved ? saved_version : 0); - editor_data.get_undo_redo().add_do_method(this, "set_current_scene", p_tab); - editor_data.get_undo_redo().add_do_method(this, "set_current_version", next_scene_version == 0 ? editor_data.get_undo_redo().get_version() + 1 : next_scene_version); - - editor_data.get_undo_redo().add_undo_method(this, "set_current_version", next_scene_version); - editor_data.get_undo_redo().add_undo_method(this, "set_current_scene", editor_data.get_edited_scene()); - editor_data.get_undo_redo().add_undo_method(this, "set_current_version", saved_version); - editor_data.get_undo_redo().commit_action(); + set_current_scene(p_tab); } Button *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) { @@ -5629,7 +5643,7 @@ void EditorNode::reload_scene(const String &p_path) { if (scene_idx == -1) { if (get_edited_scene()) { // Scene is not open, so at it might be instantiated. We'll refresh the whole scene later. - editor_data.get_undo_redo().clear_history(); + editor_data.get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id()); } return; } @@ -5645,7 +5659,7 @@ void EditorNode::reload_scene(const String &p_path) { // Adjust index so tab is back a the previous position. editor_data.move_edited_scene_to_index(scene_idx); - get_undo_redo()->clear_history(); + get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(scene_idx)); // Recover the tab. scene_tabs->set_current_tab(current_tab); @@ -5829,7 +5843,6 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process); ClassDB::bind_method("set_current_scene", &EditorNode::set_current_scene); - ClassDB::bind_method("set_current_version", &EditorNode::set_current_version); ClassDB::bind_method("_thumbnail_done", &EditorNode::_thumbnail_done); ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state); ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes); @@ -6130,7 +6143,7 @@ EditorNode::EditorNode() { rmp.instantiate(); EditorInspector::add_inspector_plugin(rmp); - Ref<EditorInspectorShaderModePlugin> smp; + Ref<EditorInspectorVisualShaderModePlugin> smp; smp.instantiate(); EditorInspector::add_inspector_plugin(smp); } @@ -6450,15 +6463,20 @@ EditorNode::EditorNode() { main_control->add_theme_constant_override("separation", 0); scene_root_parent->add_child(main_control); - HBoxContainer *left_menu_hb = memnew(HBoxContainer); - menu_hb->add_child(left_menu_hb); + bool global_menu = !bool(EDITOR_GET("interface/editor/use_embedded_menu")) && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU); - file_menu = memnew(MenuButton); - file_menu->set_flat(false); - file_menu->set_switch_on_hover(true); - file_menu->set_text(TTR("Scene")); - file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - left_menu_hb->add_child(file_menu); + main_menu = memnew(MenuBar); + menu_hb->add_child(main_menu); + main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); + main_menu->set_flat(true); + main_menu->set_start_index(0); // Main menu, add to the start of global menu. + main_menu->set_prefer_global_menu(global_menu); + main_menu->set_switch_on_hover(true); + + file_menu = memnew(PopupMenu); + file_menu->set_name(TTR("Scene")); + main_menu->add_child(file_menu); + main_menu->set_menu_tooltip(0, TTR("Operations with scene files.")); prev_scene = memnew(Button); prev_scene->set_flat(true); @@ -6528,84 +6546,75 @@ EditorNode::EditorNode() { command_palette->set_title(TTR("Command Palette")); gui_base->add_child(command_palette); - PopupMenu *p; - - file_menu->set_tooltip(TTR("Operations with scene files.")); - - p = file_menu->get_popup(); - - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_scene", TTR("New Scene"), KeyModifierMask::CMD + Key::N), FILE_NEW_SCENE); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_inherited_scene", TTR("New Inherited Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::N), FILE_NEW_INHERITED_SCENE); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/open_scene", TTR("Open Scene..."), KeyModifierMask::CMD + Key::O), FILE_OPEN_SCENE); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::T), FILE_OPEN_PREV); - p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_scene", TTR("New Scene"), KeyModifierMask::CMD + Key::N), FILE_NEW_SCENE); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_inherited_scene", TTR("New Inherited Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::N), FILE_NEW_INHERITED_SCENE); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/open_scene", TTR("Open Scene..."), KeyModifierMask::CMD + Key::O), FILE_OPEN_SCENE); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::T), FILE_OPEN_PREV); + file_menu->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KeyModifierMask::CMD + Key::S), FILE_SAVE_SCENE); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene_as", TTR("Save Scene As..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::S), FILE_SAVE_AS_SCENE); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_all_scenes", TTR("Save All Scenes"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::S), FILE_SAVE_ALL_SCENES); + file_menu->add_separator(); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KeyModifierMask::CMD + Key::S), FILE_SAVE_SCENE); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene_as", TTR("Save Scene As..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::S), FILE_SAVE_AS_SCENE); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_all_scenes", TTR("Save All Scenes"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::S), FILE_SAVE_ALL_SCENES); - p->add_separator(); + file_menu->add_separator(); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_scene", TTR("Quick Open Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::O), FILE_QUICK_OPEN_SCENE); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_script", TTR("Quick Open Script..."), KeyModifierMask::CMD + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN_SCRIPT); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_scene", TTR("Quick Open Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::O), FILE_QUICK_OPEN_SCENE); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_script", TTR("Quick Open Script..."), KeyModifierMask::CMD + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN_SCRIPT); - p->add_separator(); + file_menu->add_separator(); export_as_menu = memnew(PopupMenu); export_as_menu->set_name("Export"); - p->add_child(export_as_menu); - p->add_submenu_item(TTR("Export As..."), "Export"); + file_menu->add_child(export_as_menu); + file_menu->add_submenu_item(TTR("Export As..."), "Export"); export_as_menu->add_shortcut(ED_SHORTCUT("editor/export_as_mesh_library", TTR("MeshLibrary...")), FILE_EXPORT_MESH_LIBRARY); export_as_menu->connect("index_pressed", callable_mp(this, &EditorNode::_export_as_menu_option)); - p->add_separator(); - p->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO, true); - p->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true); + file_menu->add_separator(); + file_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO, true); + file_menu->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/close_scene", TTR("Close Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::W), FILE_CLOSE); + file_menu->add_separator(); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/close_scene", TTR("Close Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::W), FILE_CLOSE); recent_scenes = memnew(PopupMenu); recent_scenes->set_name("RecentScenes"); - p->add_child(recent_scenes); + file_menu->add_child(recent_scenes); recent_scenes->connect("id_pressed", callable_mp(this, &EditorNode::_open_recent_scene)); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KeyModifierMask::CMD + Key::Q), FILE_QUIT, true); - - project_menu = memnew(MenuButton); - project_menu->set_flat(false); - project_menu->set_switch_on_hover(true); - project_menu->set_tooltip(TTR("Miscellaneous project or scene-wide tools.")); - project_menu->set_text(TTR("Project")); - project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - left_menu_hb->add_child(project_menu); + if (!global_menu || !OS::get_singleton()->has_feature("macos")) { + // On macOS "Quit" and "About" options are in the "app" menu. + file_menu->add_separator(); + file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KeyModifierMask::CMD + Key::Q), FILE_QUIT, true); + } - p = project_menu->get_popup(); + project_menu = memnew(PopupMenu); + project_menu->set_name(TTR("Project")); + main_menu->add_child(project_menu); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/project_settings", TTR("Project Settings..."), Key::NONE, TTR("Project Settings")), RUN_SETTINGS); - p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/project_settings", TTR("Project Settings..."), Key::NONE, TTR("Project Settings")), RUN_SETTINGS); + project_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); vcs_actions_menu = VersionControlEditorPlugin::get_singleton()->get_version_control_actions_panel(); vcs_actions_menu->set_name("Version Control"); vcs_actions_menu->connect("index_pressed", callable_mp(this, &EditorNode::_version_control_menu_option)); - p->add_separator(); - p->add_child(vcs_actions_menu); - p->add_submenu_item(TTR("Version Control"), "Version Control"); + project_menu->add_separator(); + project_menu->add_child(vcs_actions_menu); + project_menu->add_submenu_item(TTR("Version Control"), "Version Control"); vcs_actions_menu->add_item(TTR("Create Version Control Metadata"), RUN_VCS_METADATA); vcs_actions_menu->add_item(TTR("Set Up Version Control"), RUN_VCS_SETTINGS); vcs_actions_menu->add_item(TTR("Shut Down Version Control"), RUN_VCS_SHUT_DOWN); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT); - p->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE); - p->add_item(TTR("Open User Data Folder"), RUN_USER_DATA_FOLDER); + project_menu->add_separator(); + project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT); + project_menu->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE); + project_menu->add_item(TTR("Open User Data Folder"), RUN_USER_DATA_FOLDER); - p->add_separator(); - p->add_item(TTR("Customize Engine Build Configuration..."), TOOLS_BUILD_PROFILE_MANAGER); - p->add_separator(); + project_menu->add_separator(); + project_menu->add_item(TTR("Customize Engine Build Configuration..."), TOOLS_BUILD_PROFILE_MANAGER); + project_menu->add_separator(); plugin_config_dialog = memnew(PluginConfigDialog); plugin_config_dialog->connect("plugin_ready", callable_mp(this, &EditorNode::_on_plugin_ready)); @@ -6614,15 +6623,15 @@ EditorNode::EditorNode() { tool_menu = memnew(PopupMenu); tool_menu->set_name("Tools"); tool_menu->connect("index_pressed", callable_mp(this, &EditorNode::_tool_menu_option)); - p->add_child(tool_menu); - p->add_submenu_item(TTR("Tools"), "Tools"); + project_menu->add_child(tool_menu); + project_menu->add_submenu_item(TTR("Tools"), "Tools"); tool_menu->add_item(TTR("Orphan Resource Explorer..."), TOOLS_ORPHAN_RESOURCES); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RELOAD_CURRENT_PROJECT); + project_menu->add_separator(); + project_menu->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RELOAD_CURRENT_PROJECT); ED_SHORTCUT_AND_COMMAND("editor/quit_to_project_list", TTR("Quit to Project List"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::Q); ED_SHORTCUT_OVERRIDE("editor/quit_to_project_list", "macos", KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::Q); - p->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true); + project_menu->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true); menu_hb->add_spacer(); @@ -6630,85 +6639,79 @@ EditorNode::EditorNode() { menu_hb->add_child(main_editor_button_vb); // Options are added and handled by DebuggerEditorPlugin. - debug_menu = memnew(MenuButton); - debug_menu->set_flat(false); - debug_menu->set_switch_on_hover(true); - debug_menu->set_text(TTR("Debug")); - debug_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - left_menu_hb->add_child(debug_menu); + debug_menu = memnew(PopupMenu); + debug_menu->set_name(TTR("Debug")); + main_menu->add_child(debug_menu); menu_hb->add_spacer(); - settings_menu = memnew(MenuButton); - settings_menu->set_flat(false); - settings_menu->set_switch_on_hover(true); - settings_menu->set_text(TTR("Editor")); - settings_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - left_menu_hb->add_child(settings_menu); - - p = settings_menu->get_popup(); + settings_menu = memnew(PopupMenu); + settings_menu->set_name(TTR("Editor")); + main_menu->add_child(settings_menu); ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings...")); ED_SHORTCUT_OVERRIDE("editor/editor_settings", "macos", KeyModifierMask::CMD + Key::COMMA); - p->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES); - p->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE); - p->add_separator(); + settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES); + settings_menu->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE); + settings_menu->add_separator(); editor_layouts = memnew(PopupMenu); editor_layouts->set_name("Layouts"); - p->add_child(editor_layouts); + settings_menu->add_child(editor_layouts); editor_layouts->connect("id_pressed", callable_mp(this, &EditorNode::_layout_menu_option)); - p->add_submenu_item(TTR("Editor Layout"), "Layouts"); - p->add_separator(); + settings_menu->add_submenu_item(TTR("Editor Layout"), "Layouts"); + settings_menu->add_separator(); ED_SHORTCUT_AND_COMMAND("editor/take_screenshot", TTR("Take Screenshot"), KeyModifierMask::CTRL | Key::F12); ED_SHORTCUT_OVERRIDE("editor/take_screenshot", "macos", KeyModifierMask::CMD | Key::F12); - p->add_shortcut(ED_GET_SHORTCUT("editor/take_screenshot"), EDITOR_SCREENSHOT); + settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/take_screenshot"), EDITOR_SCREENSHOT); - p->set_item_tooltip(-1, TTR("Screenshots are stored in the Editor Data/Settings Folder.")); + settings_menu->set_item_tooltip(-1, TTR("Screenshots are stored in the Editor Data/Settings Folder.")); ED_SHORTCUT_AND_COMMAND("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KeyModifierMask::SHIFT | Key::F11); ED_SHORTCUT_OVERRIDE("editor/fullscreen_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::F); - p->add_shortcut(ED_GET_SHORTCUT("editor/fullscreen_mode"), SETTINGS_TOGGLE_FULLSCREEN); + settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/fullscreen_mode"), SETTINGS_TOGGLE_FULLSCREEN); - p->add_separator(); + settings_menu->add_separator(); if (OS::get_singleton()->get_data_path() == OS::get_singleton()->get_config_path()) { // Configuration and data folders are located in the same place (Windows/MacOS). - p->add_item(TTR("Open Editor Data/Settings Folder"), SETTINGS_EDITOR_DATA_FOLDER); + settings_menu->add_item(TTR("Open Editor Data/Settings Folder"), SETTINGS_EDITOR_DATA_FOLDER); } else { // Separate configuration and data folders (Linux). - p->add_item(TTR("Open Editor Data Folder"), SETTINGS_EDITOR_DATA_FOLDER); - p->add_item(TTR("Open Editor Settings Folder"), SETTINGS_EDITOR_CONFIG_FOLDER); + settings_menu->add_item(TTR("Open Editor Data Folder"), SETTINGS_EDITOR_DATA_FOLDER); + settings_menu->add_item(TTR("Open Editor Settings Folder"), SETTINGS_EDITOR_CONFIG_FOLDER); } - p->add_separator(); + settings_menu->add_separator(); - p->add_item(TTR("Manage Editor Features..."), SETTINGS_MANAGE_FEATURE_PROFILES); - p->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES); + settings_menu->add_item(TTR("Manage Editor Features..."), SETTINGS_MANAGE_FEATURE_PROFILES); + settings_menu->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES); - help_menu = memnew(MenuButton); - help_menu->set_flat(false); - help_menu->set_switch_on_hover(true); - help_menu->set_text(TTR("Help")); - help_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles"))); - left_menu_hb->add_child(help_menu); + help_menu = memnew(PopupMenu); + help_menu->set_name(TTR("Help")); + main_menu->add_child(help_menu); - p = help_menu->get_popup(); - p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + help_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); ED_SHORTCUT_AND_COMMAND("editor/editor_help", TTR("Search Help"), Key::F1); ED_SHORTCUT_OVERRIDE("editor/editor_help", "macos", KeyModifierMask::ALT | Key::SPACE); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_GET_SHORTCUT("editor/editor_help"), HELP_SEARCH); - p->add_separator(); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/online_docs", TTR("Online Documentation")), HELP_DOCS); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/q&a", TTR("Questions & Answers")), HELP_QA); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/community", TTR("Community")), HELP_COMMUNITY); - p->add_separator(); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/about", TTR("About Godot")), HELP_ABOUT); - p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT); + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_GET_SHORTCUT("editor/editor_help"), HELP_SEARCH); + help_menu->add_separator(); + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/online_docs", TTR("Online Documentation")), HELP_DOCS); + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/q&a", TTR("Questions & Answers")), HELP_QA); + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG); + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE); + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK); + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/community", TTR("Community")), HELP_COMMUNITY); + help_menu->add_separator(); + if (!global_menu || !OS::get_singleton()->has_feature("macos")) { + // On macOS "Quit" and "About" options are in the "app" menu. + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/about", TTR("About Godot")), HELP_ABOUT); + } + help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT); + + Control *right_spacer = memnew(Control); + menu_hb->add_child(right_spacer); HBoxContainer *play_hb = memnew(HBoxContainer); menu_hb->add_child(play_hb); @@ -6857,7 +6860,7 @@ EditorNode::EditorNode() { right_menu_hb->add_child(update_spinner); update_spinner->set_icon(gui_base->get_theme_icon(SNAME("Progress1"), SNAME("EditorIcons"))); update_spinner->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); - p = update_spinner->get_popup(); + PopupMenu *p = update_spinner->get_popup(); p->add_radio_check_item(TTR("Update Continuously"), SETTINGS_UPDATE_CONTINUOUSLY); p->add_radio_check_item(TTR("Update When Changed"), SETTINGS_UPDATE_WHEN_CHANGED); p->add_separator(); @@ -7077,11 +7080,11 @@ EditorNode::EditorNode() { gui_base->add_child(file_script); file_script->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action)); - file_menu->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + file_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); file_menu->connect("about_to_popup", callable_mp(this, &EditorNode::_update_file_menu_opened)); - file_menu->get_popup()->connect("popup_hide", callable_mp(this, &EditorNode::_update_file_menu_closed)); + file_menu->connect("popup_hide", callable_mp(this, &EditorNode::_update_file_menu_closed)); - settings_menu->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); + settings_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); file->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action)); file_templates->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action)); @@ -7364,11 +7367,14 @@ EditorNode::EditorNode() { screenshot_timer = memnew(Timer); screenshot_timer->set_one_shot(true); - screenshot_timer->set_wait_time(settings_menu->get_popup()->get_submenu_popup_delay() + 0.1f); + screenshot_timer->set_wait_time(settings_menu->get_submenu_popup_delay() + 0.1f); screenshot_timer->connect("timeout", callable_mp(this, &EditorNode::_request_screenshot)); add_child(screenshot_timer); screenshot_timer->set_owner(get_owner()); + main_menu->set_custom_minimum_size(Size2(MAX(main_menu->get_minimum_size().x, play_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x), 0)); + right_spacer->set_custom_minimum_size(Size2(MAX(0, main_menu->get_minimum_size().x - play_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0)); + String exec = OS::get_singleton()->get_executable_path(); // Save editor executable path for third-party tools. EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec); |