FSUI: Add Themes

pull/3380/head
KamFretoZ 15 hours ago
parent 15fde6a51b
commit 857c9fe8c2

@ -368,7 +368,9 @@ static void DrawStringListSetting(SettingsInterface* bsi, const char* title, con
const char* key, const char* default_value, std::span<const char* const> options,
std::span<const char* const> 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<typename DataType, typename SizeType>
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<const char* const> options,
std::span<const char* const> 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<const char* const> options,
std::span<const char* const> 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<SmallString> 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<size_t>(index)));
{
cd_options.emplace_back(TRANSLATE_STR(tr_context, options[i]),
(value.has_value() && i == static_cast<size_t>(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<u32>(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<u32>(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"),

@ -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<std::string, std::shared_ptr<GPUTexture>> 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<u32>(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);
}
}
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);
}
}

@ -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();

Loading…
Cancel
Save