diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index ccf27ff98..62695e5db 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -368,7 +368,9 @@ static void DrawStringListSetting(SettingsInterface* bsi, const char* title, con const char* key, const char* default_value, std::span options, std::span option_values, bool enabled = true, float height = ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, - ImFont* font = UIStyle.LargeFont, ImFont* summary_font = UIStyle.MediumFont); + ImFont* font = UIStyle.LargeFont, ImFont* summary_font = UIStyle.MediumFont, + void (*changed_callback)(std::string_view) = nullptr, + const char* tr_context = TR_CONTEXT); template static void DrawEnumSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, DataType default_value, @@ -655,7 +657,7 @@ bool FullscreenUI::Initialize() if (s_state.tried_to_initialize) return false; - ImGuiFullscreen::SetTheme(Host::GetBaseBoolSettingValue("Main", "UseLightFullscreenUITheme", false)); + ImGuiFullscreen::SetTheme(Host::GetBaseStringSettingValue("UI", "FullscreenUITheme", "Dark")); ImGuiFullscreen::SetSmoothScrolling(Host::GetBaseBoolSettingValue("Main", "FullscreenUISmoothScrolling", true)); ImGuiFullscreen::UpdateLayoutScale(); @@ -2987,12 +2989,12 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit } } -[[maybe_unused]] void FullscreenUI::DrawStringListSetting(SettingsInterface* bsi, const char* title, - const char* summary, const char* section, const char* key, - const char* default_value, - std::span options, - std::span option_values, bool enabled, - float height, ImFont* font, ImFont* summary_font) +[[maybe_unused]] void +FullscreenUI::DrawStringListSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, + const char* key, const char* default_value, std::span options, + std::span option_values, bool enabled, float height, + ImFont* font, ImFont* summary_font, void (*changed_callback)(std::string_view), + const char* tr_context) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value(bsi->GetOptionalSmallStringValue( @@ -3014,8 +3016,9 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit } if (MenuButtonWithValue(title, summary, - value.has_value() ? ((index < options.size()) ? options[index] : FSUI_CSTR("Unknown")) : - FSUI_CSTR("Use Global Setting"), + value.has_value() ? + ((index < options.size()) ? TRANSLATE(tr_context, options[index]) : FSUI_CSTR("Unknown")) : + FSUI_CSTR("Use Global Setting"), enabled, height, font, summary_font)) { ImGuiFullscreen::ChoiceDialogOptions cd_options; @@ -3023,9 +3026,13 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit if (game_settings) cd_options.emplace_back(FSUI_CSTR("Use Global Setting"), !value.has_value()); for (size_t i = 0; i < options.size(); i++) - cd_options.emplace_back(options[i], (value.has_value() && i == static_cast(index))); + { + cd_options.emplace_back(TRANSLATE_STR(tr_context, options[i]), + (value.has_value() && i == static_cast(index))); + } OpenChoiceDialog(title, false, std::move(cd_options), - [game_settings, section, key, option_values](s32 index, const std::string& title, bool checked) { + [game_settings, section, key, default_value, option_values, + changed_callback](s32 index, const std::string& title, bool checked) { if (index < 0) return; @@ -3037,10 +3044,16 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit bsi->DeleteValue(section, key); else bsi->SetStringValue(section, key, option_values[index - 1]); + + if (changed_callback) + changed_callback(Host::GetStringSettingValue(section, key, default_value)); } else { bsi->SetStringValue(section, key, option_values[index]); + + if (changed_callback) + changed_callback(option_values[index]); } SetSettingsChanged(bsi); @@ -3674,6 +3687,15 @@ void FullscreenUI::DrawInterfaceSettingsPage() { SettingsInterface* bsi = GetEditingSettingsInterface(); + static constexpr const char* s_theme_name[] = { + FSUI_NSTR("Dark"), FSUI_NSTR("Light"), FSUI_NSTR("AMOLED"), + FSUI_NSTR("Cobalt Sky"), FSUI_NSTR("Grey Matter"), FSUI_NSTR("Pinky Pals"), + }; + + static constexpr const char* s_theme_value[] = { + "Dark", "Light", "AMOLED", "CobaltSky", "GreyMatter", "PinkyPals", + }; + BeginMenuButtons(); MenuHeading(FSUI_CSTR("Behavior")); @@ -3713,80 +3735,81 @@ void FullscreenUI::DrawInterfaceSettingsPage() FSUI_CSTR("Prevents the screen saver from activating and the host from sleeping while emulation is running."), "Main", "InhibitScreensaver", true); - if (const TinyString current_value = - bsi->GetTinyStringValue("Main", "FullscreenUIBackground", DEFAULT_BACKGROUND_NAME); - MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_IMAGE, "Menu Background"), - FSUI_CSTR("Shows a background image or shader when a game isn't running. Backgrounds are " - "located in resources/fullscreenui/backgrounds in the data directory."), - current_value.c_str())) - { - ChoiceDialogOptions options = GetBackgroundOptions(current_value); - OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_IMAGE, "Menu Background"), false, std::move(options), - [](s32 index, const std::string& title, bool checked) { - if (index < 0) - return; - - SettingsInterface* bsi = GetEditingSettingsInterface(); - bsi->SetStringValue("Main", "FullscreenUIBackground", (index == 0) ? "None" : title.c_str()); - SetSettingsChanged(bsi); - - // Have to defer the reload, because we've already drawn the bg for this frame. - Host::RunOnCPUThread([]() { GPUThread::RunOnThread(&FullscreenUI::LoadBackground); }); - }); - } - - if (DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Use Light Theme"), - FSUI_CSTR("Uses a light coloured theme instead of the default dark theme."), "Main", - "UseLightFullscreenUITheme", false)) - { - ImGuiFullscreen::SetTheme(bsi->GetBoolValue("Main", "UseLightFullscreenUITheme", false)); - } - - if (DrawToggleSetting( - bsi, FSUI_ICONSTR(ICON_PF_GAMEPAD, "Use DualShock/DualSense Button Icons"), - FSUI_CSTR( - "Displays DualShock/DualSense button icons in the footer and input binding, instead of Xbox buttons."), - "Main", "FullscreenUIDisplayPSIcons", false)) - { - if (bsi->GetBoolValue("Main", "FullscreenUIDisplayPSIcons", false)) - ImGuiFullscreen::SetFullscreenFooterTextIconMapping(s_ps_button_mapping); - else - ImGuiFullscreen::SetFullscreenFooterTextIconMapping({}); - } - - if (DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LIST, "Smooth Scrolling"), - FSUI_CSTR("Enables smooth scrolling of menus in Big Picture UI."), "Main", - "FullscreenUISmoothScrolling", true)) - { - ImGuiFullscreen::SetSmoothScrolling(bsi->GetBoolValue("Main", "FullscreenUISmoothScrolling", false)); - } - - { - // Have to do this the annoying way, because it's host-derived. - const auto language_list = Host::GetAvailableLanguageList(); - TinyString current_language = bsi->GetTinyStringValue("Main", "Language", ""); - const char* current_language_name = "Unknown"; - for (const auto& [language, code] : language_list) - { - if (current_language == code) - current_language_name = language; + MenuHeading(FSUI_CSTR("Appearance")); + + DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Theme"), + FSUI_CSTR("Selects the color style to be used for Big Picture UI."), "UI", "FullscreenUITheme", + "Dark", s_theme_name, s_theme_value, true, LAYOUT_MENU_BUTTON_HEIGHT, UIStyle.LargeFont, + UIStyle.MediumFont, &ImGuiFullscreen::SetTheme); + + if (const TinyString current_value = + bsi->GetTinyStringValue("Main", "FullscreenUIBackground", DEFAULT_BACKGROUND_NAME); + MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_IMAGE, "Menu Background"), + FSUI_CSTR("Shows a background image or shader when a game isn't running. Backgrounds are " + "located in resources/fullscreenui/backgrounds in the data directory."), + current_value.c_str())) + { + ChoiceDialogOptions options = GetBackgroundOptions(current_value); + OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_IMAGE, "Menu Background"), false, std::move(options), + [](s32 index, const std::string& title, bool checked) { + if (index < 0) + return; + + SettingsInterface* bsi = GetEditingSettingsInterface(); + bsi->SetStringValue("Main", "FullscreenUIBackground", (index == 0) ? "None" : title.c_str()); + SetSettingsChanged(bsi); + + // Have to defer the reload, because we've already drawn the bg for this frame. + Host::RunOnCPUThread([]() { GPUThread::RunOnThread(&FullscreenUI::LoadBackground); }); + }); } - if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_LANGUAGE, "UI Language"), - FSUI_CSTR("Chooses the language used for UI elements."), current_language_name)) + { - ImGuiFullscreen::ChoiceDialogOptions options; + // Have to do this the annoying way, because it's host-derived. + const auto language_list = Host::GetAvailableLanguageList(); + TinyString current_language = bsi->GetTinyStringValue("Main", "Language", ""); + const char* current_language_name = "Unknown"; for (const auto& [language, code] : language_list) - options.emplace_back(fmt::format("{} [{}]", language, code), (current_language == code)); - OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_LANGUAGE, "UI Language"), false, std::move(options), - [language_list](s32 index, const std::string& title, bool checked) { - if (static_cast(index) >= language_list.size()) - return; - - Host::RunOnCPUThread( - [language = language_list[index].second]() { Host::ChangeLanguage(language); }); - }); + { + if (current_language == code) + current_language_name = language; + } + if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_LANGUAGE, "UI Language"), + FSUI_CSTR("Chooses the language used for UI elements."), current_language_name)) + { + ImGuiFullscreen::ChoiceDialogOptions options; + for (const auto& [language, code] : language_list) + options.emplace_back(fmt::format("{} [{}]", language, code), (current_language == code)); + OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_LANGUAGE, "UI Language"), false, std::move(options), + [language_list](s32 index, const std::string& title, bool checked) { + if (static_cast(index) >= language_list.size()) + return; + + Host::RunOnCPUThread( + [language = language_list[index].second]() { Host::ChangeLanguage(language); }); + }); + } } - } + + if (DrawToggleSetting( + bsi, FSUI_ICONSTR(ICON_PF_GAMEPAD, "Use DualShock/DualSense Button Icons"), + FSUI_CSTR( + "Displays DualShock/DualSense button icons in the footer and input binding, instead of Xbox buttons."), + "Main", "FullscreenUIDisplayPSIcons", false)) + { + if (bsi->GetBoolValue("Main", "FullscreenUIDisplayPSIcons", false)) + ImGuiFullscreen::SetFullscreenFooterTextIconMapping(s_ps_button_mapping); + else + ImGuiFullscreen::SetFullscreenFooterTextIconMapping({}); + } + + if (DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LIST, "Smooth Scrolling"), + FSUI_CSTR("Enables smooth scrolling of menus in Big Picture UI."), "Main", + "FullscreenUISmoothScrolling", true)) + { + ImGuiFullscreen::SetSmoothScrolling(bsi->GetBoolValue("Main", "FullscreenUISmoothScrolling", false)); + } + MenuHeading(FSUI_CSTR("Integration")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CHARGING_STATION, "Enable Discord Presence"), diff --git a/src/util/imgui_fullscreen.cpp b/src/util/imgui_fullscreen.cpp index aa29ba1a4..f7023ac58 100644 --- a/src/util/imgui_fullscreen.cpp +++ b/src/util/imgui_fullscreen.cpp @@ -125,7 +125,6 @@ struct ALIGN_TO_CACHE_LINE UIState ImGuiDir has_pending_nav_move = ImGuiDir_None; FocusResetType focus_reset_queued = FocusResetType::None; bool initialized = false; - bool light_theme = false; bool smooth_scrolling = false; LRUCache> texture_cache{128, true}; @@ -1977,7 +1976,7 @@ void ImGuiFullscreen::DrawShadowedText(ImDrawList* dl, ImFont* font, const ImVec const char* text_end /*= nullptr*/, float wrap_width /*= 0.0f*/) { dl->AddText(font, font->FontSize, pos + LayoutScale(1.0f, 1.0f), - s_state.light_theme ? IM_COL32(255, 255, 255, 100) : IM_COL32(0, 0, 0, 100), text, text_end, wrap_width); + IM_COL32(0, 0, 0, 100), text, text_end, wrap_width); dl->AddText(font, font->FontSize, pos, col, text, text_end, wrap_width); } @@ -3258,10 +3257,9 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing) ImFont* const title_font = ImGuiFullscreen::UIStyle.LargeFont; ImFont* const text_font = ImGuiFullscreen::UIStyle.MediumFont; - const u32 toast_background_color = - s_state.light_theme ? IM_COL32(241, 241, 241, 255) : IM_COL32(0x28, 0x28, 0x28, 255); - const u32 toast_title_color = s_state.light_theme ? IM_COL32(1, 1, 1, 255) : IM_COL32(0xff, 0xff, 0xff, 255); - const u32 toast_text_color = s_state.light_theme ? IM_COL32(0, 0, 0, 255) : IM_COL32(0xff, 0xff, 0xff, 255); + const u32 toast_background_color = IM_COL32(0x28, 0x28, 0x28, 255); + const u32 toast_title_color = IM_COL32(0xff, 0xff, 0xff, 255); + const u32 toast_text_color = IM_COL32(0xff, 0xff, 0xff, 255); for (u32 index = 0; index < static_cast(s_state.notifications.size());) { @@ -3447,11 +3445,9 @@ void ImGuiFullscreen::DrawToast() } } -void ImGuiFullscreen::SetTheme(bool light) +void ImGuiFullscreen::SetTheme(std::string_view theme) { - s_state.light_theme = light; - - if (!light) + if (theme == "Dark") { // dark UIStyle.BackgroundColor = HEX_TO_IMVEC4(0x212121, 0xff); @@ -3472,7 +3468,7 @@ void ImGuiFullscreen::SetTheme(bool light) UIStyle.SecondaryWeakColor = HEX_TO_IMVEC4(0x002171, 0xff); UIStyle.SecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); } - else + else if (theme == "Light") { // light UIStyle.BackgroundColor = HEX_TO_IMVEC4(0xc8c8c8, 0xff); @@ -3493,4 +3489,84 @@ void ImGuiFullscreen::SetTheme(bool light) UIStyle.SecondaryWeakColor = HEX_TO_IMVEC4(0xc0cfff, 0xff); UIStyle.SecondaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff); } -} \ No newline at end of file + else if (theme == "AMOLED") + { + UIStyle.BackgroundColor = HEX_TO_IMVEC4(0x000000, 0xff); + UIStyle.BackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.BackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff); + UIStyle.BackgroundHighlight = HEX_TO_IMVEC4(0x0c0c0c, 0xff); + UIStyle.PopupBackgroundColor = HEX_TO_IMVEC4(0x212121, 0xf2); + UIStyle.PopupFrameBackgroundColor = HEX_TO_IMVEC4(0x313131, 0xf2); + UIStyle.PrimaryColor = HEX_TO_IMVEC4(0x0a0a0a, 0xff); + UIStyle.PrimaryLightColor = HEX_TO_IMVEC4(0xb5b5b5, 0xff); + UIStyle.PrimaryDarkColor = HEX_TO_IMVEC4(0x000000, 0xff); + UIStyle.PrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.DisabledColor = HEX_TO_IMVEC4(0x8d8d8d, 0xff); + UIStyle.TextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff); + UIStyle.PrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.SecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff); + UIStyle.SecondaryStrongColor = HEX_TO_IMVEC4(0x191919, 0xff); + UIStyle.SecondaryWeakColor = HEX_TO_IMVEC4(0x474747, 0xff); + UIStyle.SecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + } + else if (theme == "CobaltSky") + { + UIStyle.BackgroundColor = HEX_TO_IMVEC4(0x2b3760, 0xff); + UIStyle.BackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.BackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff); + UIStyle.BackgroundHighlight = HEX_TO_IMVEC4(0x3b54ac, 0xff); + UIStyle.PopupBackgroundColor = HEX_TO_IMVEC4(0x2b3760, 0xf2); + UIStyle.PopupFrameBackgroundColor = HEX_TO_IMVEC4(0x3b54ac, 0xf2); + UIStyle.PrimaryColor = HEX_TO_IMVEC4(0x202e5a, 0xff); + UIStyle.PrimaryLightColor = HEX_TO_IMVEC4(0xb5b5b5, 0xff); + UIStyle.PrimaryDarkColor = HEX_TO_IMVEC4(0x000000, 0xff); + UIStyle.PrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.DisabledColor = HEX_TO_IMVEC4(0x8d8d8d, 0xff); + UIStyle.TextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff); + UIStyle.PrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.SecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff); + UIStyle.SecondaryStrongColor = HEX_TO_IMVEC4(0x245dda, 0xff); + UIStyle.SecondaryWeakColor = HEX_TO_IMVEC4(0x3a3d7b, 0xff); + UIStyle.SecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + } + else if (theme == "GreyMatter") + { + UIStyle.BackgroundColor = HEX_TO_IMVEC4(0x353944, 0xff); + UIStyle.BackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.BackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff); + UIStyle.BackgroundHighlight = HEX_TO_IMVEC4(0x484d57, 0xff); + UIStyle.PopupFrameBackgroundColor = HEX_TO_IMVEC4(0x313131, 0xf2); + UIStyle.PopupBackgroundColor = HEX_TO_IMVEC4(0x212121, 0xf2); + UIStyle.PrimaryColor = HEX_TO_IMVEC4(0x292d35, 0xff); + UIStyle.PrimaryLightColor = HEX_TO_IMVEC4(0xb5b5b5, 0xff); + UIStyle.PrimaryDarkColor = HEX_TO_IMVEC4(0x000000, 0xff); + UIStyle.PrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.DisabledColor = HEX_TO_IMVEC4(0x8d8d8d, 0xff); + UIStyle.TextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff); + UIStyle.PrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.SecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff); + UIStyle.SecondaryStrongColor = HEX_TO_IMVEC4(0x191919, 0xff); + UIStyle.SecondaryWeakColor = HEX_TO_IMVEC4(0x2a2e36, 0xff); + UIStyle.SecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff); + } + else if (theme == "PinkyPals") + { + UIStyle.BackgroundColor = HEX_TO_IMVEC4(0xeba0b9, 0xff); + UIStyle.BackgroundTextColor = HEX_TO_IMVEC4(0x000000, 0xff); + UIStyle.BackgroundLineColor = HEX_TO_IMVEC4(0xe05885, 0xff); + UIStyle.BackgroundHighlight = HEX_TO_IMVEC4(0xe05885, 0xff); + UIStyle.PopupFrameBackgroundColor = HEX_TO_IMVEC4(0xe05885, 0xf2); + UIStyle.PopupBackgroundColor = HEX_TO_IMVEC4(0xeba0b9, 0xf2); + UIStyle.PrimaryColor = HEX_TO_IMVEC4(0xffaec9, 0xff); + UIStyle.PrimaryLightColor = HEX_TO_IMVEC4(0xe05885, 0xff); + UIStyle.PrimaryDarkColor = HEX_TO_IMVEC4(0xeba0b9, 0xff); + UIStyle.PrimaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff); + UIStyle.DisabledColor = HEX_TO_IMVEC4(0x4b4b4b, 0xff); + UIStyle.TextHighlightColor = HEX_TO_IMVEC4(0xeba0b9, 0xff); + UIStyle.PrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff); + UIStyle.SecondaryColor = HEX_TO_IMVEC4(0xe05885, 0xff); + UIStyle.SecondaryStrongColor = HEX_TO_IMVEC4(0xdc6c68, 0xff); + UIStyle.SecondaryWeakColor = HEX_TO_IMVEC4(0xab5451, 0xff); + UIStyle.SecondaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff); + } +} diff --git a/src/util/imgui_fullscreen.h b/src/util/imgui_fullscreen.h index 228e2cfdc..c153cf408 100644 --- a/src/util/imgui_fullscreen.h +++ b/src/util/imgui_fullscreen.h @@ -62,6 +62,8 @@ struct ALIGN_TO_CACHE_LINE UIStyles ImVec4 SecondaryWeakColor; // Not currently used. ImVec4 SecondaryStrongColor; ImVec4 SecondaryTextColor; + ImVec4 ToastBackgroundColor; + ImVec4 ToastTextColor; ImFont* MediumFont; ImFont* LargeFont; @@ -128,7 +130,7 @@ ImRect FitImage(const ImVec2& fit_size, const ImVec2& image_size); /// Initializes, setting up any state. bool Initialize(const char* placeholder_image_path); -void SetTheme(bool light); +void SetTheme(std::string_view theme); void SetSmoothScrolling(bool enabled); void SetFonts(ImFont* medium_font, ImFont* large_font); bool UpdateLayoutScale();