FullscreenUI: Polish achievements page

This commit is contained in:
Stenzek 2025-06-22 00:29:43 +10:00
parent d18910a619
commit 68fa33e075
No known key found for this signature in database
5 changed files with 235 additions and 77 deletions

View File

@ -140,8 +140,6 @@ static bool TryLoggingInWithToken();
static void EnableHardcodeMode(bool display_message, bool display_game_summary);
static void OnHardcoreModeChanged(bool enabled, bool display_message, bool display_game_summary);
static bool IsRAIntegrationInitializing();
static bool IsLoggedIn();
static bool IsLoggedInOrLoggingIn();
static void FinishInitialize();
static void FinishLogin(const rc_client_t* client);
static void ShowLoginNotification();
@ -2181,6 +2179,19 @@ std::string Achievements::GetLoggedInUserBadgePath()
return badge_path;
}
SmallString Achievements::GetLoggedInUserPointsSummary()
{
SmallString ret;
const rc_client_user_t* user = rc_client_get_user_info(s_state.client);
if (!user) [[unlikely]]
return ret;
//: Score summary, shown in Big Picture mode.
ret.format(TRANSLATE_FS("Achievements", "Score: {} ({} softcore)"), user->score, user->score_softcore);
return ret;
}
u32 Achievements::GetPauseThrottleFrames()
{
if (!IsActive() || !IsHardcoreModeActive())

View File

@ -166,6 +166,12 @@ const std::string& GetGameTitle();
/// Returns the path for the game that is current hashed/running.
const std::string& GetGamePath();
/// Returns true if the user has been successfully logged in.
bool IsLoggedIn();
/// Returns true if the user has been successfully logged in, or the request is in progress.
bool IsLoggedInOrLoggingIn();
/// Returns the logged-in user name.
const char* GetLoggedInUserName();
@ -173,6 +179,10 @@ const char* GetLoggedInUserName();
/// Should be called with the lock held.
std::string GetLoggedInUserBadgePath();
/// Returns a summary of the user's points.
/// Should be called with the lock held.
SmallString GetLoggedInUserPointsSummary();
/// Returns 0 if pausing is allowed, otherwise the number of frames until pausing is allowed.
u32 GetPauseThrottleFrames();

View File

@ -323,7 +323,8 @@ static void DrawAudioSettingsPage();
static void DrawMemoryCardSettingsPage();
static void DrawControllerSettingsPage();
static void DrawHotkeySettingsPage();
static void DrawAchievementsSettingsPage();
static void DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& settings_lock);
static void DrawAchievementsSettingsHeader(SettingsInterface* bsi, std::unique_lock<std::mutex>& settings_lock);
static void DrawAchievementsLoginWindow();
static void DrawAdvancedSettingsPage();
static void DrawPatchesOrCheatsSettingsPage(bool cheats);
@ -493,6 +494,7 @@ static constexpr std::array s_theme_values = {"", "Dark", "Light
static constexpr std::string_view RESUME_STATE_SELECTOR_DIALOG_NAME = "##resume_state_selector";
static constexpr std::string_view ABOUT_DIALOG_NAME = "##about_duckstation";
static constexpr std::string_view ACHIEVEMENTS_LOGIN_DIALOG_NAME = "##achievements_login";
//////////////////////////////////////////////////////////////////////////
// State
@ -3962,8 +3964,6 @@ void FullscreenUI::DrawSettingsWindow()
s_state.settings_last_bg_alpha),
0.0f, ImVec2(LAYOUT_MENU_WINDOW_X_PADDING, 0.0f)))
{
ResetFocusHere();
if (ImGui::IsWindowFocused() && WantsToCloseMenu())
ReturnToPreviousWindow();
@ -4020,7 +4020,7 @@ void FullscreenUI::DrawSettingsWindow()
break;
case SettingsPage::Achievements:
DrawAchievementsSettingsPage();
DrawAchievementsSettingsPage(lock);
break;
case SettingsPage::Advanced:
@ -4063,6 +4063,7 @@ void FullscreenUI::DrawSettingsWindow()
void FullscreenUI::DrawSummarySettingsPage()
{
BeginMenuButtons();
ResetFocusHere();
MenuHeading(FSUI_VSTR("Details"));
@ -4137,6 +4138,7 @@ void FullscreenUI::DrawInterfaceSettingsPage()
SettingsInterface* bsi = GetEditingSettingsInterface();
BeginMenuButtons();
ResetFocusHere();
MenuHeading(FSUI_VSTR("Appearance"));
@ -4349,6 +4351,7 @@ void FullscreenUI::DrawBIOSSettingsPage()
const bool game_settings = IsEditingGameSettings(bsi);
BeginMenuButtons();
ResetFocusHere();
MenuHeading(FSUI_VSTR("BIOS Selection"));
@ -4443,6 +4446,7 @@ void FullscreenUI::DrawConsoleSettingsPage()
SettingsInterface* bsi = GetEditingSettingsInterface();
BeginMenuButtons();
ResetFocusHere();
MenuHeading(FSUI_VSTR("Console Settings"));
@ -4574,6 +4578,7 @@ void FullscreenUI::DrawEmulationSettingsPage()
SettingsInterface* bsi = GetEditingSettingsInterface();
BeginMenuButtons();
ResetFocusHere();
MenuHeading(FSUI_VSTR("Speed Control"));
DrawFloatListSetting(
@ -4807,6 +4812,7 @@ void FullscreenUI::DrawControllerSettingsPage()
const bool game_settings = IsEditingGameSettings(bsi);
MenuHeading(FSUI_VSTR("Configuration"));
ResetFocusHere();
if (IsEditingGameSettings(bsi))
{
@ -5186,6 +5192,7 @@ void FullscreenUI::DrawHotkeySettingsPage()
SettingsInterface* bsi = GetEditingSettingsInterface();
BeginMenuButtons();
ResetFocusHere();
const HotkeyInfo* last_category = nullptr;
for (const HotkeyInfo* hotkey : s_state.hotkey_list_cache)
@ -5214,6 +5221,8 @@ void FullscreenUI::DrawMemoryCardSettingsPage()
BeginMenuButtons();
MenuHeading(FSUI_VSTR("Settings and Operations"));
ResetFocusHere();
DrawFolderSetting(bsi, FSUI_ICONVSTR(ICON_FA_FOLDER_OPEN, "Memory Card Directory"), "MemoryCards", "Directory",
EmuFolders::MemoryCards);
@ -5334,6 +5343,7 @@ void FullscreenUI::DrawGraphicsSettingsPage()
MenuHeading(FSUI_VSTR("Device Settings"));
ResetFocusHere();
DrawEnumSetting(bsi, FSUI_ICONVSTR(ICON_PF_PICTURE, "GPU Renderer"),
FSUI_VSTR("Selects the backend to use for rendering the console/game visuals."), "GPU", "Renderer",
Settings::DEFAULT_GPU_RENDERER, &Settings::ParseRendererName, &Settings::GetRendererName,
@ -5788,6 +5798,7 @@ void FullscreenUI::DrawPostProcessingSettingsPage()
BeginMenuButtons();
MenuHeading(FSUI_VSTR("Controls"));
ResetFocusHere();
reload_pending |= DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_WAND_MAGIC_SPARKLES, "Enable Post Processing"),
FSUI_VSTR("If not enabled, the current post processing chain will be ignored."),
@ -6198,6 +6209,7 @@ void FullscreenUI::DrawAudioSettingsPage()
BeginMenuButtons();
MenuHeading(FSUI_VSTR("Audio Control"));
ResetFocusHere();
DrawIntRangeSetting(bsi, FSUI_ICONVSTR(ICON_FA_VOLUME_HIGH, "Output Volume"),
FSUI_VSTR("Controls the volume of the audio played on the host."), "Audio", "OutputVolume", 100,
@ -6243,13 +6255,145 @@ void FullscreenUI::DrawAudioSettingsPage()
EndMenuButtons();
}
void FullscreenUI::DrawAchievementsSettingsPage()
void FullscreenUI::DrawAchievementsSettingsHeader(SettingsInterface* bsi, std::unique_lock<std::mutex>& settings_lock)
{
ImDrawList* const dl = ImGui::GetWindowDrawList();
const float panel_height = LayoutScale(100.0f);
const float panel_rounding = LayoutScale(20.0f);
const float spacing = LayoutScale(10.0f);
const float line_spacing = LayoutScale(5.0f);
const float badge_size = LayoutScale(60.0f);
const ImGuiStyle& style = ImGui::GetStyle();
const ImVec2 bg_pos = ImGui::GetCursorScreenPos() + ImVec2(0.0f, spacing * 2.0f);
const ImVec2 bg_size = ImVec2(ImGui::GetContentRegionAvail().x, LayoutScale(100.0f));
dl->AddRectFilled(bg_pos, bg_pos + bg_size,
ImGui::GetColorU32(ModAlpha(DarkerColor(UIStyle.BackgroundColor), GetBackgroundAlpha())),
panel_rounding);
// must be after background rect
BeginMenuButtons();
ImVec2 pos = bg_pos + ImVec2(panel_rounding, panel_rounding);
const float max_content_width = bg_size.x - panel_rounding;
const ImVec2 pos_backup = ImGui::GetCursorPos();
TinyString username;
std::string_view badge_path;
SmallString score_summary;
const bool logged_in = (bsi->ContainsValue("Cheevos", "Token"));
{
// avoid locking order issues
settings_lock.unlock();
{
const auto lock = Achievements::GetLock();
if (s_state.achievements_user_badge_path.empty()) [[unlikely]]
s_state.achievements_user_badge_path = Achievements::GetLoggedInUserBadgePath();
badge_path = s_state.achievements_user_badge_path;
if (badge_path.empty())
badge_path = "images/ra-generic-user.png";
if (Achievements::IsLoggedIn())
{
const char* username_ptr = Achievements::GetLoggedInUserName();
if (username_ptr)
username = username_ptr;
}
else if (Achievements::IsLoggedInOrLoggingIn())
{
username = FSUI_VSTR("Logging In...");
}
else if (!logged_in)
{
username = FSUI_VSTR("Not Logged In");
}
else
{
// client not active
username = bsi->GetSmallStringValue("Cheevos", "Username");
}
score_summary = Achievements::GetLoggedInUserPointsSummary();
if (score_summary.empty())
{
if (logged_in)
score_summary = FSUI_VSTR("Enable Achievements to see your user summary.");
else
score_summary = FSUI_VSTR("To use achievements, please log in with your retroachievements.org account.");
}
}
settings_lock.lock();
}
if (GPUTexture* badge_tex = GetCachedTextureAsync(badge_path))
{
const ImRect badge_rect =
ImGuiFullscreen::CenterImage(ImRect(pos, pos + ImVec2(badge_size, badge_size)), badge_tex);
dl->AddImage(reinterpret_cast<ImTextureID>(GetCachedTextureAsync(badge_path)), badge_rect.Min, badge_rect.Max);
}
pos.x += badge_size + LayoutScale(15.0f);
RenderShadowedTextClipped(dl, UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, pos,
pos + ImVec2(max_content_width - pos.x, UIStyle.LargeFontSize),
ImGui::GetColorU32(ImGuiCol_Text), username);
pos.y += UIStyle.LargeFontSize + line_spacing;
ImGuiFullscreen::RenderAutoLabelText(dl, UIStyle.Font, UIStyle.MediumLargeFontSize, UIStyle.NormalFontWeight,
UIStyle.BoldFontWeight, pos,
pos + ImVec2(max_content_width - pos.x, UIStyle.LargeFontSize),
ImGui::GetColorU32(ImGuiCol_Text), score_summary, ':');
if (!IsEditingGameSettings(bsi))
{
const auto login_logout_text =
logged_in ? FSUI_ICONVSTR(ICON_FA_KEY, "Logout") : FSUI_ICONVSTR(ICON_FA_KEY, "Login");
const ImVec2 login_logout_button_size =
UIStyle.Font->CalcTextSizeA(UIStyle.LargeFontSize, UIStyle.BoldFontWeight, FLT_MAX, 0.0f,
IMSTR_START_END(login_logout_text)) +
style.FramePadding * 2.0f;
const ImVec2 login_logout_button_pos =
ImVec2(bg_pos.x + bg_size.x - panel_rounding - login_logout_button_size.x - LayoutScale(10.0f),
bg_pos.y + ((panel_height - UIStyle.LargeFontSize - (style.FramePadding.y * 2.0f)) * 0.5f));
ImGui::SetCursorPos(login_logout_button_pos);
bool visible, hovered;
const bool clicked = MenuButtonFrame(
"login_logout", true, ImRect(login_logout_button_pos, login_logout_button_pos + login_logout_button_size),
&visible, &hovered);
if (visible)
{
const ImRect text_bb = ImRect(login_logout_button_pos + style.FramePadding,
login_logout_button_pos + login_logout_button_size - style.FramePadding);
RenderShadowedTextClipped(dl, UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, text_bb.Min,
text_bb.Max, ImGui::GetColorU32(ImGuiCol_Text), login_logout_text, nullptr,
ImVec2(0.0f, 0.0f), 0.0f, &text_bb);
}
if (clicked)
{
if (logged_in)
Host::RunOnCPUThread(&Achievements::Logout);
else
OpenFixedPopupDialog(ACHIEVEMENTS_LOGIN_DIALOG_NAME);
}
}
ImGui::SetCursorPos(ImVec2(pos_backup.x, pos_backup.y + panel_height + (spacing * 3.0f)));
}
void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& settings_lock)
{
SettingsInterface* bsi = GetEditingSettingsInterface();
BeginMenuButtons();
DrawAchievementsSettingsHeader(bsi, settings_lock);
MenuHeading(FSUI_VSTR("Settings"));
ResetFocusHere();
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_TROPHY, "Enable Achievements"),
FSUI_VSTR("When enabled and logged in, DuckStation will scan for achievements on startup."),
"Cheevos", "Enabled", false);
@ -6264,6 +6408,8 @@ void FullscreenUI::DrawAchievementsSettingsPage()
{
if (GPUThread::HasGPUBackend() && bsi->GetBoolValue("Cheevos", "ChallengeMode", false))
{
// prevent locking order deadlock
settings_lock.unlock();
const auto lock = Achievements::GetLock();
if (Achievements::HasActiveGame())
{
@ -6275,6 +6421,7 @@ void FullscreenUI::DrawAchievementsSettingsPage()
Host::RunOnCPUThread(&System::ResetSystem);
});
}
settings_lock.lock();
}
}
@ -6308,14 +6455,19 @@ void FullscreenUI::DrawAchievementsSettingsPage()
if (!IsEditingGameSettings(bsi))
{
MenuHeading(FSUI_VSTR("Account"));
if (MenuButton(FSUI_ICONVSTR(ICON_FA_LIST_OL, "Update Progress"),
FSUI_VSTR("Updates the progress database for achievements shown in the game list.")))
{
Host::RunOnCPUThread([]() {
Error error;
if (!Achievements::RefreshAllProgressDatabase(&error))
ImGuiFullscreen::ShowToast(FSUI_STR("Failed to update progress database"), error.TakeDescription(),
Host::OSD_ERROR_DURATION);
});
}
if (bsi->ContainsValue("Cheevos", "Token"))
{
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]);
MenuButtonWithoutSummary(SmallString::from_format(fmt::runtime(FSUI_ICONVSTR(ICON_FA_USER, "Username: {}")),
bsi->GetTinyStringValue("Cheevos", "Username")),
false);
TinyString ts_string;
ts_string.format(
FSUI_FSTR("{:%Y-%m-%d %H:%M:%S}"),
@ -6324,60 +6476,13 @@ void FullscreenUI::DrawAchievementsSettingsPage()
MenuButtonWithoutSummary(
SmallString::from_format(fmt::runtime(FSUI_ICONVSTR(ICON_FA_CLOCK, "Login token generated on {}")), ts_string),
false);
ImGui::PopStyleColor();
if (MenuButton(FSUI_ICONVSTR(ICON_FA_LIST_OL, "Update Progress"),
FSUI_VSTR("Updates the progress database for achievements shown in the game list.")))
{
Host::RunOnCPUThread([]() {
Error error;
if (!Achievements::RefreshAllProgressDatabase(&error))
ImGuiFullscreen::ShowToast(FSUI_STR("Failed to update progress database"), error.TakeDescription(),
Host::OSD_ERROR_DURATION);
});
}
if (MenuButton(FSUI_ICONVSTR(ICON_FA_KEY, "Logout"), FSUI_VSTR("Logs out of RetroAchievements.")))
Host::RunOnCPUThread(&Achievements::Logout);
}
else
{
MenuButtonWithoutSummary(FSUI_ICONVSTR(ICON_FA_USER, "Not Logged In"), false);
static constexpr std::string_view popup_title = "##achievements_login";
if (MenuButton(FSUI_ICONVSTR(ICON_FA_KEY, "Login"), FSUI_VSTR("Logs in to RetroAchievements.")))
OpenFixedPopupDialog(popup_title);
if (IsFixedPopupDialogOpen(popup_title))
DrawAchievementsLoginWindow();
}
MenuHeading(FSUI_VSTR("Current Game"));
if (Achievements::HasActiveGame())
{
const auto lock = Achievements::GetLock();
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]);
MenuButtonWithoutSummary(SmallString::from_format(fmt::runtime(FSUI_ICONVSTR(ICON_FA_BOOKMARK, "Game: {} ({})")),
Achievements::GetGameID(), Achievements::GetGameTitle()),
false);
const std::string& rich_presence_string = Achievements::GetRichPresenceString();
if (!rich_presence_string.empty())
MenuButtonWithoutSummary(SmallString::from_format(ICON_FA_MAP "{}", rich_presence_string), false);
else
MenuButtonWithoutSummary(FSUI_ICONVSTR(ICON_FA_MAP, "Rich presence inactive or unsupported."), false);
ImGui::PopStyleColor();
}
else
{
MenuButtonWithoutSummary(FSUI_ICONVSTR(ICON_FA_BAN, "Game not loaded or no RetroAchievements available."), false);
}
}
EndMenuButtons();
if (IsFixedPopupDialogOpen(ACHIEVEMENTS_LOGIN_DIALOG_NAME))
DrawAchievementsLoginWindow();
}
void FullscreenUI::DrawAchievementsLoginWindow()
@ -6499,6 +6604,8 @@ void FullscreenUI::DrawAdvancedSettingsPage()
BeginMenuButtons();
MenuHeading(FSUI_VSTR("Logging Settings"));
ResetFocusHere();
DrawEnumSetting(bsi, FSUI_VSTR("Log Level"),
FSUI_VSTR("Sets the verbosity of messages logged. Higher levels will log more messages."), "Logging",
"LogLevel", Settings::DEFAULT_LOG_LEVEL, &Settings::ParseLogLevelName, &Settings::GetLogLevelName,
@ -6583,6 +6690,7 @@ void FullscreenUI::DrawPatchesOrCheatsSettingsPage(bool cheats)
const char* section = cheats ? Cheats::CHEATS_CONFIG_SECTION : Cheats::PATCHES_CONFIG_SECTION;
BeginMenuButtons();
ResetFocusHere();
static constexpr auto draw_code = [](SettingsInterface* bsi, const char* section, const Cheats::CodeInfo& ci,
std::vector<std::string>& enable_list, bool cheats) {
@ -8469,6 +8577,7 @@ void FullscreenUI::DrawGameListSettingsPage()
SettingsInterface* bsi = GetEditingSettingsInterface(false);
BeginMenuButtons();
ResetFocusHere();
MenuHeading(FSUI_VSTR("List Settings"));
{
@ -9170,7 +9279,6 @@ TRANSLATE_NOOP("FullscreenUI", "9x (for 4K)");
TRANSLATE_NOOP("FullscreenUI", "A cover already exists for this game. Are you sure that you want to overwrite it?");
TRANSLATE_NOOP("FullscreenUI", "AMOLED");
TRANSLATE_NOOP("FullscreenUI", "About");
TRANSLATE_NOOP("FullscreenUI", "Account");
TRANSLATE_NOOP("FullscreenUI", "Achievement Notifications");
TRANSLATE_NOOP("FullscreenUI", "Achievement Unlock/Count");
TRANSLATE_NOOP("FullscreenUI", "Achievements");
@ -9289,7 +9397,6 @@ TRANSLATE_NOOP("FullscreenUI", "Create New...");
TRANSLATE_NOOP("FullscreenUI", "Create Save State Backups");
TRANSLATE_NOOP("FullscreenUI", "Crop Mode");
TRANSLATE_NOOP("FullscreenUI", "Culling Correction");
TRANSLATE_NOOP("FullscreenUI", "Current Game");
TRANSLATE_NOOP("FullscreenUI", "Custom");
TRANSLATE_NOOP("FullscreenUI", "Dark");
TRANSLATE_NOOP("FullscreenUI", "Dark Ruby");
@ -9358,6 +9465,7 @@ TRANSLATE_NOOP("FullscreenUI", "Emulation Settings");
TRANSLATE_NOOP("FullscreenUI", "Emulation Speed");
TRANSLATE_NOOP("FullscreenUI", "Enable 8MB RAM");
TRANSLATE_NOOP("FullscreenUI", "Enable Achievements");
TRANSLATE_NOOP("FullscreenUI", "Enable Achievements to see your user summary.");
TRANSLATE_NOOP("FullscreenUI", "Enable Cheats");
TRANSLATE_NOOP("FullscreenUI", "Enable Discord Presence");
TRANSLATE_NOOP("FullscreenUI", "Enable Fast Boot");
@ -9446,7 +9554,6 @@ TRANSLATE_NOOP("FullscreenUI", "Game Properties");
TRANSLATE_NOOP("FullscreenUI", "Game Quick Save");
TRANSLATE_NOOP("FullscreenUI", "Game Slot {0}##game_slot_{0}");
TRANSLATE_NOOP("FullscreenUI", "Game compatibility rating copied to clipboard.");
TRANSLATE_NOOP("FullscreenUI", "Game not loaded or no RetroAchievements available.");
TRANSLATE_NOOP("FullscreenUI", "Game path copied to clipboard.");
TRANSLATE_NOOP("FullscreenUI", "Game region copied to clipboard.");
TRANSLATE_NOOP("FullscreenUI", "Game serial copied to clipboard.");
@ -9454,7 +9561,6 @@ TRANSLATE_NOOP("FullscreenUI", "Game settings have been cleared for '{}'.");
TRANSLATE_NOOP("FullscreenUI", "Game settings initialized with global settings for '{}'.");
TRANSLATE_NOOP("FullscreenUI", "Game title copied to clipboard.");
TRANSLATE_NOOP("FullscreenUI", "Game type copied to clipboard.");
TRANSLATE_NOOP("FullscreenUI", "Game: {} ({})");
TRANSLATE_NOOP("FullscreenUI", "Genre: ");
TRANSLATE_NOOP("FullscreenUI", "Geometry Tolerance");
TRANSLATE_NOOP("FullscreenUI", "GitHub Repository");
@ -9506,6 +9612,7 @@ TRANSLATE_NOOP("FullscreenUI", "Log Level");
TRANSLATE_NOOP("FullscreenUI", "Log To Debug Console");
TRANSLATE_NOOP("FullscreenUI", "Log To File");
TRANSLATE_NOOP("FullscreenUI", "Log To System Console");
TRANSLATE_NOOP("FullscreenUI", "Logging In...");
TRANSLATE_NOOP("FullscreenUI", "Logging Settings");
TRANSLATE_NOOP("FullscreenUI", "Logging in to RetroAchievements...");
TRANSLATE_NOOP("FullscreenUI", "Login");
@ -9513,11 +9620,9 @@ TRANSLATE_NOOP("FullscreenUI", "Login Failed.\nError: {}\nPlease check your user
TRANSLATE_NOOP("FullscreenUI", "Login token generated on {}");
TRANSLATE_NOOP("FullscreenUI", "Logout");
TRANSLATE_NOOP("FullscreenUI", "Logs BIOS calls to printf(). Not all games contain debugging messages.");
TRANSLATE_NOOP("FullscreenUI", "Logs in to RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Logs messages to duckstation.log in the user directory.");
TRANSLATE_NOOP("FullscreenUI", "Logs messages to the console window.");
TRANSLATE_NOOP("FullscreenUI", "Logs messages to the debug console where supported.");
TRANSLATE_NOOP("FullscreenUI", "Logs out of RetroAchievements.");
TRANSLATE_NOOP("FullscreenUI", "Macro Button {}");
TRANSLATE_NOOP("FullscreenUI", "Makes games run closer to their console framerate, at a small cost to performance.");
TRANSLATE_NOOP("FullscreenUI", "Maximum");
@ -9652,7 +9757,6 @@ TRANSLATE_NOOP("FullscreenUI", "Rewind Save Slots");
TRANSLATE_NOOP("FullscreenUI", "Rewind for {0} frames, lasting {1:.2f} seconds will require up to {2} MB of RAM and {3} MB of VRAM.");
TRANSLATE_NOOP("FullscreenUI", "Rewind is disabled because runahead is enabled. Runahead will significantly increase system requirements.");
TRANSLATE_NOOP("FullscreenUI", "Rewind is not enabled. Please note that enabling rewind may significantly increase system requirements.");
TRANSLATE_NOOP("FullscreenUI", "Rich presence inactive or unsupported.");
TRANSLATE_NOOP("FullscreenUI", "Round Upscaled Texture Coordinates");
TRANSLATE_NOOP("FullscreenUI", "Rounds texture coordinates instead of flooring when upscaling. Can fix misaligned textures in some games, but break others, and is incompatible with texture filtering.");
TRANSLATE_NOOP("FullscreenUI", "Runahead");
@ -9803,6 +9907,7 @@ TRANSLATE_NOOP("FullscreenUI", "Time Played");
TRANSLATE_NOOP("FullscreenUI", "Time Played: ");
TRANSLATE_NOOP("FullscreenUI", "Timing out in {:.0f} seconds...");
TRANSLATE_NOOP("FullscreenUI", "Title");
TRANSLATE_NOOP("FullscreenUI", "To use achievements, please log in with your retroachievements.org account.");
TRANSLATE_NOOP("FullscreenUI", "Toggle Analog");
TRANSLATE_NOOP("FullscreenUI", "Toggle Fast Forward");
TRANSLATE_NOOP("FullscreenUI", "Toggle Fullscreen");
@ -9830,7 +9935,6 @@ TRANSLATE_NOOP("FullscreenUI", "Use Separate Disc Settings");
TRANSLATE_NOOP("FullscreenUI", "Use Single Card For Multi-Disc Games");
TRANSLATE_NOOP("FullscreenUI", "Use Software Renderer For Readbacks");
TRANSLATE_NOOP("FullscreenUI", "User Name");
TRANSLATE_NOOP("FullscreenUI", "Username: {}");
TRANSLATE_NOOP("FullscreenUI", "Uses PGXP for all instructions, not just memory operations.");
TRANSLATE_NOOP("FullscreenUI", "Uses a blit presentation model instead of flipping. This may be needed on some systems.");
TRANSLATE_NOOP("FullscreenUI", "Uses a second thread for drawing graphics. Provides a significant speed improvement particularly with the software renderer, and is safe to use.");

View File

@ -52,8 +52,6 @@ static void DrawLoadingScreen(std::string_view image, std::string_view message,
s32 progress_value, bool is_persistent);
static void DrawNotifications(ImVec2& position, float spacing);
static void DrawToast();
static bool MenuButtonFrame(std::string_view str_id, bool enabled, const ImRect& bb, bool* visible, bool* hovered,
ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f);
static ImGuiID GetBackgroundProgressID(std::string_view str_id);
namespace {
@ -1683,6 +1681,36 @@ void ImGuiFullscreen::RenderShadowedTextClipped(ImFont* font, float font_size, f
text_size_if_known, align, wrap_width, clip_rect);
}
void ImGuiFullscreen::RenderAutoLabelText(ImDrawList* draw_list, ImFont* font, float font_size, float font_weight,
float label_weight, const ImVec2& pos_min, const ImVec2& pos_max, u32 color,
std::string_view text, char separator, float shadow_offset)
{
const std::string_view::size_type label_end = text.find(separator);
ImVec2 text_pos = pos_min;
std::string_view remaining;
if (label_end != std::string_view::npos)
{
// include label in bold part
const std::string_view label = text.substr(0, label_end + 1);
const ImVec2 size = font->CalcTextSizeA(font_size, font_weight, FLT_MAX, 0.0f, IMSTR_START_END(label));
RenderShadowedTextClipped(draw_list, font, font_size, label_weight, text_pos, pos_max, color, label, &size,
ImVec2(0.0f, 0.0f), 0.0f, nullptr, shadow_offset);
text_pos.x += size.x;
remaining = text.substr(label_end + 1);
}
else
{
remaining = text;
}
const ImVec2 size = font->CalcTextSizeA(font_size, font_weight, FLT_MAX, 0.0f, IMSTR_START_END(remaining));
RenderShadowedTextClipped(draw_list, font, font_size, font_weight, text_pos, pos_max, color, remaining, &size,
ImVec2(0.0f, 0.0f), 0.0f, nullptr, shadow_offset);
}
void ImGuiFullscreen::TextAlignedMultiLine(float align_x, const char* text, const char* text_end, float wrap_width)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
@ -1937,11 +1965,11 @@ bool ImGuiFullscreen::FloatingButton(std::string_view text, float x, float y, fl
{
const ImVec2 text_size = UIStyle.Font->CalcTextSizeA(UIStyle.LargeFontSize, UIStyle.BoldFontWeight,
std::numeric_limits<float>::max(), 0.0f, IMSTR_START_END(text));
const ImVec2& padding(ImGui::GetStyle().FramePadding);
const ImVec2& padding = ImGui::GetStyle().FramePadding;
const float width = (padding.x * 2.0f) + text_size.x;
const float height = (padding.y * 2.0f) + text_size.y;
const ImVec2 window_size(ImGui::GetWindowSize());
const ImVec2 window_size = ImGui::GetWindowSize();
if (anchor_x == -1.0f)
x -= width;
else if (anchor_x == -0.5f)

View File

@ -283,6 +283,8 @@ void EndMenuButtons();
float GetMenuButtonAvailableWidth();
bool MenuButtonFrame(std::string_view str_id, float height, bool enabled, ImRect* item_bb, bool* visible, bool* hovered,
ImGuiButtonFlags flags = 0, float alpha = 1.0f);
bool MenuButtonFrame(std::string_view str_id, bool enabled, const ImRect& bb, bool* visible, bool* hovered,
ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f);
void DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_max, ImU32 fill_col, bool border = true);
void ResetMenuButtonFrame();
void RenderShadowedTextClipped(ImFont* font, float font_size, float font_weight, const ImVec2& pos_min,
@ -297,6 +299,9 @@ void RenderShadowedTextClipped(ImDrawList* draw_list, ImFont* font, float font_s
const ImVec2& pos_min, const ImVec2& pos_max, u32 color, std::string_view text,
const ImVec2* text_size_if_known, const ImVec2& align, float wrap_width,
const ImRect* clip_rect, float shadow_offset);
void RenderAutoLabelText(ImDrawList* draw_list, ImFont* font, float font_size, float font_weight, float label_weight,
const ImVec2& pos_min, const ImVec2& pos_max, u32 color, std::string_view text,
char separator = ':', float shadow_offset = LayoutScale(LAYOUT_SHADOW_OFFSET));
void TextAlignedMultiLine(float align_x, const char* text, const char* text_end = nullptr, float wrap_width = -1.0f);
void MenuHeading(std::string_view title, bool draw_line = true);
bool MenuHeadingButton(std::string_view title, std::string_view value = {}, bool enabled = true, bool draw_line = true);