diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 579b526b5ebb..3691172c1803 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -498,40 +498,43 @@ void EditorNode::_update_theme(bool p_skip_creation) { update_preview_themes(CanvasItemEditor::THEME_PREVIEW_EDITOR); } - gui_base->add_theme_style_override("panel", theme->get_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); - main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, theme->get_constant(SNAME("window_border_margin"), EditorStringName(Editor))); - main_vbox->add_theme_constant_override("separation", theme->get_constant(SNAME("top_bar_separation"), EditorStringName(Editor))); + // Update styles. + { + gui_base->add_theme_style_override("panel", theme->get_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); + main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, theme->get_constant(SNAME("window_border_margin"), EditorStringName(Editor))); + main_vbox->add_theme_constant_override("separation", theme->get_constant(SNAME("top_bar_separation"), EditorStringName(Editor))); - scene_root_parent->add_theme_style_override("panel", theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles))); - bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles))); - main_menu->add_theme_style_override("hover", theme->get_stylebox(SNAME("MenuHover"), EditorStringName(EditorStyles))); - distraction_free->set_icon(theme->get_icon(SNAME("DistractionFree"), EditorStringName(EditorIcons))); - bottom_panel_raise->set_icon(theme->get_icon(SNAME("ExpandBottomDock"), EditorStringName(EditorIcons))); + scene_root_parent->add_theme_style_override("panel", theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles))); + bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles))); + main_menu->add_theme_style_override("hover", theme->get_stylebox(SNAME("MenuHover"), EditorStringName(EditorStyles))); + distraction_free->set_icon(theme->get_icon(SNAME("DistractionFree"), EditorStringName(EditorIcons))); + bottom_panel_raise->set_icon(theme->get_icon(SNAME("ExpandBottomDock"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), theme->get_icon(SNAME("HelpSearch"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_DOCS), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_QA), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_REPORT_A_BUG), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_COPY_SYSTEM_INFO), theme->get_icon(SNAME("ActionCopy"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_SUGGEST_A_FEATURE), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_SEND_DOCS_FEEDBACK), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_COMMUNITY), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_ABOUT), theme->get_icon(SNAME("Godot"), EditorStringName(EditorIcons))); - help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), theme->get_icon(SNAME("Heart"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), theme->get_icon(SNAME("HelpSearch"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_DOCS), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_QA), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_REPORT_A_BUG), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_COPY_SYSTEM_INFO), theme->get_icon(SNAME("ActionCopy"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_SUGGEST_A_FEATURE), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_SEND_DOCS_FEEDBACK), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_COMMUNITY), theme->get_icon(SNAME("ExternalLink"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_ABOUT), theme->get_icon(SNAME("Godot"), EditorStringName(EditorIcons))); + help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), theme->get_icon(SNAME("Heart"), EditorStringName(EditorIcons))); - if (EditorDebuggerNode::get_singleton()->is_visible()) { - bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))); - } + if (EditorDebuggerNode::get_singleton()->is_visible()) { + bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))); + } - for (int i = 0; i < main_editor_buttons.size(); i++) { - Button *tb = main_editor_buttons[i]; - EditorPlugin *p_editor = editor_table[i]; - Ref icon = p_editor->get_icon(); + for (int i = 0; i < main_editor_buttons.size(); i++) { + Button *tb = main_editor_buttons[i]; + EditorPlugin *p_editor = editor_table[i]; + Ref icon = p_editor->get_icon(); - if (icon.is_valid()) { - tb->set_icon(icon); - } else if (theme->has_icon(p_editor->get_name(), EditorStringName(EditorIcons))) { - tb->set_icon(theme->get_icon(p_editor->get_name(), EditorStringName(EditorIcons))); + if (icon.is_valid()) { + tb->set_icon(icon); + } else if (theme->has_icon(p_editor->get_name(), EditorStringName(EditorIcons))) { + tb->set_icon(theme->get_icon(p_editor->get_name(), EditorStringName(EditorIcons))); + } } } } diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 4c01df3997a2..c9234cc071bd 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -38,7 +38,6 @@ #include "core/io/stream_peer_tls.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/string/translation.h" #include "core/version.h" #include "editor/editor_about.h" #include "editor/editor_settings.h" @@ -48,6 +47,7 @@ #include "editor/project_manager/project_dialog.h" #include "editor/project_manager/project_list.h" #include "editor/project_manager/project_tag.h" +#include "editor/project_manager/quick_settings_dialog.h" #include "editor/themes/editor_icons.h" #include "editor/themes/editor_scale.h" #include "editor/themes/editor_theme_manager.h" @@ -63,6 +63,7 @@ #include "scene/gui/separator.h" #include "scene/gui/texture_rect.h" #include "scene/main/window.h" +#include "scene/theme/theme_db.h" #include "servers/display_server.h" #include "servers/navigation_server_3d.h" #include "servers/physics_server_2d.h" @@ -77,64 +78,9 @@ void ProjectManager::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { Engine::get_singleton()->set_editor_hint(false); - } break; - case NOTIFICATION_THEME_CHANGED: { - const int top_bar_separation = get_theme_constant(SNAME("top_bar_separation"), EditorStringName(Editor)); - root_container->add_theme_constant_override("margin_left", top_bar_separation); - root_container->add_theme_constant_override("margin_top", top_bar_separation); - root_container->add_theme_constant_override("margin_bottom", top_bar_separation); - root_container->add_theme_constant_override("margin_right", top_bar_separation); - main_vbox->add_theme_constant_override("separation", top_bar_separation); - - background_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); - main_view_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); - - title_bar_logo->set_icon(get_editor_theme_icon(SNAME("TitleBarLogo"))); - - _set_main_view_icon(MAIN_VIEW_PROJECTS, get_editor_theme_icon(SNAME("ProjectList"))); - _set_main_view_icon(MAIN_VIEW_ASSETLIB, get_editor_theme_icon(SNAME("AssetLib"))); - - // Project list. - { - loading_label->add_theme_font_override("font", get_theme_font(SNAME("bold"), EditorStringName(EditorFonts))); - search_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("search_panel"), SNAME("ProjectManager"))); - - // Top bar. - search_box->set_right_icon(get_editor_theme_icon(SNAME("Search"))); - language_btn->set_icon(get_editor_theme_icon(SNAME("Environment"))); - - // Sidebar. - create_btn->set_icon(get_editor_theme_icon(SNAME("Add"))); - import_btn->set_icon(get_editor_theme_icon(SNAME("Load"))); - scan_btn->set_icon(get_editor_theme_icon(SNAME("Search"))); - open_btn->set_icon(get_editor_theme_icon(SNAME("Edit"))); - run_btn->set_icon(get_editor_theme_icon(SNAME("Play"))); - rename_btn->set_icon(get_editor_theme_icon(SNAME("Rename"))); - manage_tags_btn->set_icon(get_editor_theme_icon("Script")); - erase_btn->set_icon(get_editor_theme_icon(SNAME("Remove"))); - erase_missing_btn->set_icon(get_editor_theme_icon(SNAME("Clear"))); - create_tag_btn->set_icon(get_editor_theme_icon("Add")); - - tag_error->add_theme_color_override("font_color", get_theme_color("error_color", EditorStringName(Editor))); - tag_edit_error->add_theme_color_override("font_color", get_theme_color("error_color", EditorStringName(Editor))); - - create_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - import_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - scan_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - open_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - run_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - rename_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - manage_tags_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - erase_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - erase_missing_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); - } - - // Asset library popup. - if (asset_library) { - // Removes extra border margins. - asset_library->add_theme_style_override("panel", memnew(StyleBoxEmpty)); - } + // Theme has already been created in the constructor, so we can skip that step. + _update_theme(true); } break; case NOTIFICATION_READY: { @@ -161,6 +107,12 @@ void ProjectManager::_notification(int p_what) { case NOTIFICATION_WM_ABOUT: { _show_about(); } break; + + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + if (EditorThemeManager::is_generated_theme_outdated()) { + _update_theme(); + } + } break; } } @@ -221,7 +173,94 @@ void ProjectManager::_update_size_limits() { // We try to set it to half the screen resolution, but no smaller than the minimum window size. Size2 half_screen_rect = (screen_rect.size * EDSCALE) / 2; Size2 maximum_popup_size = MAX(half_screen_rect, minimum_size); - language_btn->get_popup()->set_max_size(maximum_popup_size); + quick_settings_dialog->update_size_limits(maximum_popup_size); + } +} + +void ProjectManager::_update_theme(bool p_skip_creation) { + if (!p_skip_creation) { + theme = EditorThemeManager::generate_theme(theme); + DisplayServer::set_early_window_clear_color_override(true, theme->get_color(SNAME("background"), EditorStringName(Editor))); + } + + List> editor_themes; + editor_themes.push_back(theme); + editor_themes.push_back(ThemeDB::get_singleton()->get_default_theme()); + + ThemeContext *node_tc = ThemeDB::get_singleton()->get_theme_context(this); + if (node_tc) { + node_tc->set_themes(editor_themes); + } else { + ThemeDB::get_singleton()->create_theme_context(this, editor_themes); + } + + Window *owner_window = get_window(); + if (owner_window) { + ThemeContext *window_tc = ThemeDB::get_singleton()->get_theme_context(owner_window); + if (window_tc) { + window_tc->set_themes(editor_themes); + } else { + ThemeDB::get_singleton()->create_theme_context(owner_window, editor_themes); + } + } + + // Update styles. + { + const int top_bar_separation = get_theme_constant(SNAME("top_bar_separation"), EditorStringName(Editor)); + root_container->add_theme_constant_override("margin_left", top_bar_separation); + root_container->add_theme_constant_override("margin_top", top_bar_separation); + root_container->add_theme_constant_override("margin_bottom", top_bar_separation); + root_container->add_theme_constant_override("margin_right", top_bar_separation); + main_vbox->add_theme_constant_override("separation", top_bar_separation); + + background_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); + main_view_container->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer"))); + + title_bar_logo->set_icon(get_editor_theme_icon(SNAME("TitleBarLogo"))); + + _set_main_view_icon(MAIN_VIEW_PROJECTS, get_editor_theme_icon(SNAME("ProjectList"))); + _set_main_view_icon(MAIN_VIEW_ASSETLIB, get_editor_theme_icon(SNAME("AssetLib"))); + + // Project list. + { + loading_label->add_theme_font_override("font", get_theme_font(SNAME("bold"), EditorStringName(EditorFonts))); + search_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("search_panel"), SNAME("ProjectManager"))); + + // Top bar. + search_box->set_right_icon(get_editor_theme_icon(SNAME("Search"))); + quick_settings_button->set_icon(get_editor_theme_icon(SNAME("Tools"))); + + // Sidebar. + create_btn->set_icon(get_editor_theme_icon(SNAME("Add"))); + import_btn->set_icon(get_editor_theme_icon(SNAME("Load"))); + scan_btn->set_icon(get_editor_theme_icon(SNAME("Search"))); + open_btn->set_icon(get_editor_theme_icon(SNAME("Edit"))); + run_btn->set_icon(get_editor_theme_icon(SNAME("Play"))); + rename_btn->set_icon(get_editor_theme_icon(SNAME("Rename"))); + manage_tags_btn->set_icon(get_editor_theme_icon("Script")); + erase_btn->set_icon(get_editor_theme_icon(SNAME("Remove"))); + erase_missing_btn->set_icon(get_editor_theme_icon(SNAME("Clear"))); + create_tag_btn->set_icon(get_editor_theme_icon("Add")); + + tag_error->add_theme_color_override("font_color", get_theme_color("error_color", EditorStringName(Editor))); + tag_edit_error->add_theme_color_override("font_color", get_theme_color("error_color", EditorStringName(Editor))); + + create_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + import_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + scan_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + open_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + run_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + rename_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + manage_tags_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + erase_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + erase_missing_btn->add_theme_constant_override("h_separation", get_theme_constant(SNAME("sidebar_button_icon_separation"), SNAME("ProjectManager"))); + } + + // Asset library popup. + if (asset_library) { + // Removes extra border margins. + asset_library->add_theme_style_override("panel", memnew(StyleBoxEmpty)); + } } } @@ -350,24 +389,6 @@ void ProjectManager::_open_asset_library_confirmed() { _select_main_view(MAIN_VIEW_ASSETLIB); } -// Quick settings. - -void ProjectManager::_language_selected(int p_id) { - String lang = language_btn->get_item_metadata(p_id); - EditorSettings::get_singleton()->set("interface/editor/editor_language", lang); - - restart_required_dialog->popup_centered(); -} - -void ProjectManager::_restart_confirm() { - List args = OS::get_singleton()->get_cmdline_args(); - Error err = OS::get_singleton()->create_instance(args); - ERR_FAIL_COND(err); - - _dim_window(); - get_tree()->quit(); -} - void ProjectManager::_dim_window() { // This method must be called before calling `get_tree()->quit()`. // Otherwise, its effect won't be visible @@ -379,6 +400,21 @@ void ProjectManager::_dim_window() { set_modulate(dim_color); } +// Quick settings. + +void ProjectManager::_show_quick_settings() { + quick_settings_dialog->popup_centered(Size2(600, 200) * EDSCALE); +} + +void ProjectManager::_restart_confirmed() { + List args = OS::get_singleton()->get_cmdline_args(); + Error err = OS::get_singleton()->create_instance(args); + ERR_FAIL_COND(err); + + _dim_window(); + get_tree()->quit(); +} + // Footer. void ProjectManager::_version_button_pressed() { @@ -1048,10 +1084,9 @@ ProjectManager::ProjectManager() { Window::set_root_layout_direction(pm_root_dir); EditorThemeManager::initialize(); - Ref theme = EditorThemeManager::generate_theme(); + theme = EditorThemeManager::generate_theme(); DisplayServer::set_early_window_clear_color_override(true, theme->get_color(SNAME("background"), EditorStringName(Editor))); - set_theme(theme); set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); _build_icon_type_cache(theme); @@ -1075,67 +1110,36 @@ ProjectManager::ProjectManager() { title_bar = memnew(HBoxContainer); main_vbox->add_child(title_bar); + HBoxContainer *left_hbox = memnew(HBoxContainer); + left_hbox->set_alignment(BoxContainer::ALIGNMENT_BEGIN); + left_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL); + left_hbox->set_stretch_ratio(1.0); + title_bar->add_child(left_hbox); + title_bar_logo = memnew(Button); title_bar_logo->set_flat(true); - title_bar->add_child(title_bar_logo); + left_hbox->add_child(title_bar_logo); title_bar_logo->connect("pressed", callable_mp(this, &ProjectManager::_show_about)); - HBoxContainer *left_spacer = memnew(HBoxContainer); - left_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS); - left_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL); - title_bar->add_child(left_spacer); - main_view_toggles = memnew(HBoxContainer); + main_view_toggles->set_alignment(BoxContainer::ALIGNMENT_CENTER); + main_view_toggles->set_h_size_flags(Control::SIZE_EXPAND_FILL); + main_view_toggles->set_stretch_ratio(2.0); title_bar->add_child(main_view_toggles); main_view_toggles_group.instantiate(); - Control *right_spacer = memnew(Control); - right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS); - right_spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL); - title_bar->add_child(right_spacer); + HBoxContainer *right_hbox = memnew(HBoxContainer); + right_hbox->set_alignment(BoxContainer::ALIGNMENT_END); + right_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL); + right_hbox->set_stretch_ratio(1.0); + title_bar->add_child(right_hbox); - quick_settings_hbox = memnew(HBoxContainer); - title_bar->add_child(quick_settings_hbox); - } - - // Quick settings. - { - language_btn = memnew(OptionButton); - language_btn->set_focus_mode(Control::FOCUS_NONE); - language_btn->set_fit_to_longest_item(false); - language_btn->set_flat(true); - language_btn->connect("item_selected", callable_mp(this, &ProjectManager::_language_selected)); -#ifdef ANDROID_ENABLED - // The language selection dropdown doesn't work on Android (as the setting isn't saved), see GH-60353. - // Also, the dropdown it spawns is very tall and can't be scrolled without a hardware mouse. - language_btn->hide(); -#endif - - Vector editor_languages; - List editor_settings_properties; - EditorSettings::get_singleton()->get_property_list(&editor_settings_properties); - for (const PropertyInfo &pi : editor_settings_properties) { - if (pi.name == "interface/editor/editor_language") { - editor_languages = pi.hint_string.split(","); - break; - } - } - - String current_lang = EDITOR_GET("interface/editor/editor_language"); - language_btn->set_text(current_lang); - - for (int i = 0; i < editor_languages.size(); i++) { - const String &lang = editor_languages[i]; - String lang_name = TranslationServer::get_singleton()->get_locale_name(lang); - language_btn->add_item(vformat("[%s] %s", lang, lang_name), i); - language_btn->set_item_metadata(i, lang); - if (current_lang == lang) { - language_btn->select(i); - } - } - - quick_settings_hbox->add_child(language_btn); + quick_settings_button = memnew(Button); + quick_settings_button->set_flat(true); + quick_settings_button->set_text(TTR("Settings")); + right_hbox->add_child(quick_settings_button); + quick_settings_button->connect("pressed", callable_mp(this, &ProjectManager::_show_quick_settings)); } main_view_container = memnew(PanelContainer); @@ -1305,12 +1309,9 @@ ProjectManager::ProjectManager() { // Dialogs. { - restart_required_dialog = memnew(ConfirmationDialog); - restart_required_dialog->set_ok_button_text(TTR("Restart Now")); - restart_required_dialog->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_restart_confirm)); - restart_required_dialog->set_cancel_button_text(TTR("Continue")); - restart_required_dialog->set_text(TTR("Settings changed!\nThe project manager must be restarted for changes to take effect.")); - add_child(restart_required_dialog); + quick_settings_dialog = memnew(QuickSettingsDialog); + add_child(quick_settings_dialog); + quick_settings_dialog->connect("restart_required", callable_mp(this, &ProjectManager::_restart_confirmed)); scan_dir = memnew(EditorFileDialog); scan_dir->set_previews_enabled(false); diff --git a/editor/project_manager.h b/editor/project_manager.h index f3f443968c3f..16c7bd9dac20 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -46,6 +46,7 @@ class OptionButton; class PanelContainer; class ProjectDialog; class ProjectList; +class QuickSettingsDialog; class RichTextLabel; class TabContainer; class VBoxContainer; @@ -66,7 +67,10 @@ class ProjectManager : public Control { // Main layout. + Ref theme; + void _update_size_limits(); + void _update_theme(bool p_skip_creation = false); MarginContainer *root_container = nullptr; Panel *background_panel = nullptr; @@ -75,7 +79,7 @@ class ProjectManager : public Control { HBoxContainer *title_bar = nullptr; Button *title_bar_logo = nullptr; HBoxContainer *main_view_toggles = nullptr; - HBoxContainer *quick_settings_hbox = nullptr; + Button *quick_settings_button = nullptr; enum MainViewTab { MAIN_VIEW_PROJECTS, @@ -105,14 +109,14 @@ class ProjectManager : public Control { void _suggest_asset_library(); void _open_asset_library_confirmed(); + void _dim_window(); + // Quick settings. - OptionButton *language_btn = nullptr; - ConfirmationDialog *restart_required_dialog = nullptr; + QuickSettingsDialog *quick_settings_dialog = nullptr; - void _language_selected(int p_id); - void _restart_confirm(); - void _dim_window(); + void _show_quick_settings(); + void _restart_confirmed(); // Footer. diff --git a/editor/project_manager/quick_settings_dialog.cpp b/editor/project_manager/quick_settings_dialog.cpp new file mode 100644 index 000000000000..255b15f7f675 --- /dev/null +++ b/editor/project_manager/quick_settings_dialog.cpp @@ -0,0 +1,306 @@ +/**************************************************************************/ +/* quick_settings_dialog.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "quick_settings_dialog.h" + +#include "core/config/project_settings.h" +#include "core/string/translation.h" +#include "editor/editor_settings.h" +#include "editor/editor_string_names.h" +#include "editor/themes/editor_scale.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/label.h" +#include "scene/gui/margin_container.h" +#include "scene/gui/option_button.h" +#include "scene/gui/panel_container.h" + +void QuickSettingsDialog::_fetch_setting_values() { + editor_languages.clear(); + editor_themes.clear(); + editor_scales.clear(); + editor_network_modes.clear(); + + { + List editor_settings_properties; + EditorSettings::get_singleton()->get_property_list(&editor_settings_properties); + + for (const PropertyInfo &pi : editor_settings_properties) { + if (pi.name == "interface/editor/editor_language") { + editor_languages = pi.hint_string.split(","); + } else if (pi.name == "interface/theme/preset") { + editor_themes = pi.hint_string.split(","); + } else if (pi.name == "interface/editor/display_scale") { + editor_scales = pi.hint_string.split(","); + } else if (pi.name == "network/connection/network_mode") { + editor_network_modes = pi.hint_string.split(","); + } + } + } +} + +void QuickSettingsDialog::_update_current_values() { + // Language options. + { + const String current_lang = EDITOR_GET("interface/editor/editor_language"); + + for (int i = 0; i < editor_languages.size(); i++) { + const String &lang_value = editor_languages[i]; + if (current_lang == lang_value) { + language_option_button->set_text(current_lang); + language_option_button->select(i); + } + } + } + + // Theme options. + { + const String current_theme = EDITOR_GET("interface/theme/preset"); + + for (int i = 0; i < editor_themes.size(); i++) { + const String &theme_value = editor_themes[i]; + if (current_theme == theme_value) { + theme_option_button->set_text(current_theme); + theme_option_button->select(i); + + custom_theme_label->set_visible(current_theme == "Custom"); + } + } + } + + // Scale options. + { + const int current_scale = EDITOR_GET("interface/editor/display_scale"); + + for (int i = 0; i < editor_scales.size(); i++) { + const String &scale_value = editor_scales[i]; + if (current_scale == i) { + scale_option_button->set_text(scale_value); + scale_option_button->select(i); + } + } + } + + // Network mode options. + { + const int current_network_mode = EDITOR_GET("network/connection/network_mode"); + + for (int i = 0; i < editor_network_modes.size(); i++) { + const String &network_mode_value = editor_network_modes[i]; + if (current_network_mode == i) { + network_mode_option_button->set_text(network_mode_value); + network_mode_option_button->select(i); + } + } + } +} + +void QuickSettingsDialog::_add_setting_control(const String &p_text, Control *p_control) { + HBoxContainer *container = memnew(HBoxContainer); + settings_list->add_child(container); + + Label *label = memnew(Label(p_text)); + label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + container->add_child(label); + + p_control->set_h_size_flags(Control::SIZE_EXPAND_FILL); + p_control->set_stretch_ratio(2.0); + container->add_child(p_control); +} + +void QuickSettingsDialog::_language_selected(int p_id) { + const String selected_language = language_option_button->get_item_metadata(p_id); + _set_setting_value("interface/editor/editor_language", selected_language, true); +} + +void QuickSettingsDialog::_theme_selected(int p_id) { + const String selected_theme = theme_option_button->get_item_text(p_id); + _set_setting_value("interface/theme/preset", selected_theme); + + custom_theme_label->set_visible(selected_theme == "Custom"); +} + +void QuickSettingsDialog::_scale_selected(int p_id) { + _set_setting_value("interface/editor/display_scale", p_id, true); +} + +void QuickSettingsDialog::_network_mode_selected(int p_id) { + _set_setting_value("network/connection/network_mode", p_id); +} + +void QuickSettingsDialog::_set_setting_value(const String &p_setting, const Variant &p_value, bool p_restart_required) { + EditorSettings::get_singleton()->set(p_setting, p_value); + EditorSettings::get_singleton()->notify_changes(); + EditorSettings::get_singleton()->save(); + + if (p_restart_required) { + restart_required_label->show(); + + if (!restart_required_button) { + restart_required_button = add_button(TTR("Restart Now"), !GLOBAL_GET("gui/common/swap_cancel_ok")); + restart_required_button->connect("pressed", callable_mp(this, &QuickSettingsDialog::_request_restart)); + } + } +} + +void QuickSettingsDialog::_request_restart() { + emit_signal("restart_required"); +} + +void QuickSettingsDialog::update_size_limits(const Size2 &p_max_popup_size) { + language_option_button->get_popup()->set_max_size(p_max_popup_size); +} + +void QuickSettingsDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: { + settings_list_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("Background"), EditorStringName(EditorStyles))); + + restart_required_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); + custom_theme_label->add_theme_color_override("font_color", get_theme_color(SNAME("font_placeholder_color"), EditorStringName(Editor))); + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible()) { + _update_current_values(); + } + } break; + } +} + +void QuickSettingsDialog::_bind_methods() { + ADD_SIGNAL(MethodInfo("restart_required")); +} + +QuickSettingsDialog::QuickSettingsDialog() { + set_title(TTR("Quick Settings")); + set_ok_button_text(TTR("Close")); + + VBoxContainer *main_vbox = memnew(VBoxContainer); + add_child(main_vbox); + main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT); + + // Settings grid. + { + _fetch_setting_values(); + + settings_list_panel = memnew(PanelContainer); + main_vbox->add_child(settings_list_panel); + + settings_list = memnew(VBoxContainer); + settings_list_panel->add_child(settings_list); + + // Language options. + { + language_option_button = memnew(OptionButton); + language_option_button->set_fit_to_longest_item(false); + language_option_button->connect("item_selected", callable_mp(this, &QuickSettingsDialog::_language_selected)); + + for (int i = 0; i < editor_languages.size(); i++) { + const String &lang_value = editor_languages[i]; + String lang_name = TranslationServer::get_singleton()->get_locale_name(lang_value); + language_option_button->add_item(vformat("[%s] %s", lang_value, lang_name), i); + language_option_button->set_item_metadata(i, lang_value); + } + + _add_setting_control(TTR("Language"), language_option_button); + } + + // Theme options. + { + theme_option_button = memnew(OptionButton); + theme_option_button->set_fit_to_longest_item(false); + theme_option_button->connect("item_selected", callable_mp(this, &QuickSettingsDialog::_theme_selected)); + + for (int i = 0; i < editor_themes.size(); i++) { + const String &theme_value = editor_themes[i]; + theme_option_button->add_item(theme_value, i); + } + + _add_setting_control(TTR("Interface Theme"), theme_option_button); + + custom_theme_label = memnew(Label(TTR("Custom preset can be further configured in the editor."))); + custom_theme_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); + custom_theme_label->set_custom_minimum_size(Size2(220, 0) * EDSCALE); + custom_theme_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD); + custom_theme_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + custom_theme_label->set_stretch_ratio(2.0); + custom_theme_label->hide(); + settings_list->add_child(custom_theme_label); + } + + // Scale options. + { + scale_option_button = memnew(OptionButton); + scale_option_button->set_fit_to_longest_item(false); + scale_option_button->connect("item_selected", callable_mp(this, &QuickSettingsDialog::_scale_selected)); + + for (int i = 0; i < editor_scales.size(); i++) { + const String &scale_value = editor_scales[i]; + scale_option_button->add_item(scale_value, i); + } + + _add_setting_control(TTR("Display Scale"), scale_option_button); + } + + // Network mode options. + { + network_mode_option_button = memnew(OptionButton); + network_mode_option_button->set_fit_to_longest_item(false); + network_mode_option_button->connect("item_selected", callable_mp(this, &QuickSettingsDialog::_network_mode_selected)); + + for (int i = 0; i < editor_network_modes.size(); i++) { + const String &network_mode_value = editor_network_modes[i]; + network_mode_option_button->add_item(network_mode_value, i); + } + + _add_setting_control(TTR("Network Mode"), network_mode_option_button); + } + + _update_current_values(); + +#ifdef ANDROID_ENABLED + // The language selection dropdown doesn't work on Android (as the setting isn't saved), see GH-60353. + // Also, the dropdown it spawns is very tall and can't be scrolled without a hardware mouse. + language_option_button->hide(); + scale_option_button->hide(); +#endif + } + + // Restart required panel. + { + restart_required_label = memnew(Label(TTR("Settings changed! The project manager must be restarted for changes to take effect."))); + restart_required_label->set_custom_minimum_size(Size2(560, 0) * EDSCALE); + restart_required_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD); + restart_required_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + restart_required_label->hide(); + main_vbox->add_child(restart_required_label); + } +} diff --git a/editor/project_manager/quick_settings_dialog.h b/editor/project_manager/quick_settings_dialog.h new file mode 100644 index 000000000000..c4c4e601c937 --- /dev/null +++ b/editor/project_manager/quick_settings_dialog.h @@ -0,0 +1,87 @@ +/**************************************************************************/ +/* quick_settings_dialog.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef QUICK_SETTINGS_DIALOG_H +#define QUICK_SETTINGS_DIALOG_H + +#include "scene/gui/dialogs.h" + +class Button; +class Label; +class MarginContainer; +class OptionButton; +class PanelContainer; +class VBoxContainer; + +class QuickSettingsDialog : public AcceptDialog { + GDCLASS(QuickSettingsDialog, AcceptDialog); + + Vector editor_languages; + Vector editor_themes; + Vector editor_scales; + Vector editor_network_modes; + + void _fetch_setting_values(); + void _update_current_values(); + + PanelContainer *settings_list_panel = nullptr; + VBoxContainer *settings_list = nullptr; + + void _add_setting_control(const String &p_text, Control *p_control); + + OptionButton *language_option_button = nullptr; + OptionButton *theme_option_button = nullptr; + OptionButton *scale_option_button = nullptr; + OptionButton *network_mode_option_button = nullptr; + + Label *custom_theme_label = nullptr; + + void _language_selected(int p_id); + void _theme_selected(int p_id); + void _scale_selected(int p_id); + void _network_mode_selected(int p_id); + void _set_setting_value(const String &p_setting, const Variant &p_value, bool p_restart_required = false); + + Label *restart_required_label = nullptr; + Button *restart_required_button = nullptr; + + void _request_restart(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void update_size_limits(const Size2 &p_max_popup_size); + + QuickSettingsDialog(); +}; + +#endif // QUICK_SETTINGS_DIALOG_H