FSUI: Add custom RetroAchievements login dialog

FSUI: Add custom RetroAchievements login dialog
Signed-off-by: SternXD <stern@sidestore.io>
This commit is contained in:
SternXD 2025-05-28 19:44:49 -04:00 committed by Ty
parent b87b8eb7bb
commit b27846ce39
2 changed files with 352 additions and 1 deletions

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="275"
width="570"
version="1.1"
viewBox="0 0 150.81249 72.760419"
id="svg4"
sodipodi:docname="RetroAchievements_logo_square.svg"
inkscape:version="1.4 (86a8ad7, 2024-10-11)"
inkscape:export-filename="RetroAchievements_logo_square.png"
inkscape:export-xdpi="960"
inkscape:export-ydpi="960"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs4">
<linearGradient
id="linearGradient6"
inkscape:collect="always">
<stop
style="stop-color:#ca9800;stop-opacity:1;"
offset="0.5"
id="stop6" />
<stop
style="stop-color:#ffe080;stop-opacity:1;"
offset="1"
id="stop7" />
</linearGradient>
<linearGradient
id="linearGradient4"
inkscape:collect="always">
<stop
style="stop-color:#87b6f8;stop-opacity:1;"
offset="0"
id="stop4" />
<stop
style="stop-color:#0f65dd;stop-opacity:1;"
offset="0.50065017"
id="stop5" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4"
id="linearGradient5"
x1="229.8"
y1="-556.42499"
x2="229.8"
y2="-531.58502"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient6"
id="linearGradient7"
x1="257.58826"
y1="-529.96503"
x2="257.58826"
y2="-558.04498"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-0.66412404)" />
</defs>
<sodipodi:namedview
id="namedview4"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm"
showguides="true"
inkscape:zoom="0.54074219"
inkscape:cx="213.59532"
inkscape:cy="218.21859"
inkscape:window-width="1536"
inkscape:window-height="898"
inkscape:window-x="-6"
inkscape:window-y="-6"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<g
transform="matrix(5.6312119,0,0,5.6312119,-392.00615,-696.01846)"
id="g4">
<g
transform="matrix(0.35278,0,0,-0.35278,-4.3083,326.78)"
id="g3">
<g
aria-label="RA"
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
transform="matrix(1.1293,0,0,-1.1092,-28.246,-45.784)"
id="g2">
<path
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;fill:url(#linearGradient5)"
d="m 217.38,-553.59 h 11.73 q 1.89,0 3.12,1.14 1.26,1.14 1.26,3.45 0,0.99 -0.33,1.86 -0.33,0.84 -0.93,1.47 -0.57,0.63 -1.38,0.99 -0.81,0.36 -1.74,0.36 h -0.99 l 8.55,15.03 h -4.29 l -5.94,-10.29 v 10.29 h -3.99 v -19.17 h 6.51 q 0.24,0 0.36,-0.18 0.15,-0.18 0.15,-0.39 0,-0.21 -0.15,-0.36 -0.12,-0.18 -0.36,-0.18 h -7.59 v 20.28 h -3.99 z m 12.66,10.26 q 0.87,-0.06 1.68,-0.51 0.84,-0.45 1.47,-1.2 0.63,-0.75 1.02,-1.74 0.39,-1.02 0.39,-2.22 0,-1.23 -0.39,-2.28 -0.39,-1.05 -1.11,-1.8 -0.72,-0.75 -1.74,-1.17 -0.99,-0.42 -2.25,-0.42 h -11.73 v -4.05 h 11.73 q 1.98,0 3.72,0.75 1.74,0.75 3.03,2.07 1.29,1.32 2.01,3.09 0.75,1.77 0.75,3.81 0,2.58 -0.87,4.47 -0.87,1.86 -2.37,3 l 6.84,12.24 h -4.08 z"
id="path1" />
<path
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;fill:url(#linearGradient7)"
d="m 253.50413,-532.8 h 12.45 l -7.62,-21.15 q -0.09,-0.3 -0.54,-0.54 -0.45,-0.24 -0.87,-0.24 -0.48,0 -0.9,0.24 -0.39,0.24 -0.48,0.54 l -8.67,24.66 h -3.99 l 9.27,-26.16 q 0.21,-0.63 0.6,-1.2 0.39,-0.6 0.96,-1.05 0.6,-0.48 1.38,-0.75 0.81,-0.27 1.83,-0.27 1.02,0 1.8,0.27 0.78,0.27 1.35,0.75 0.6,0.45 0.99,1.05 0.39,0.57 0.63,1.2 l 9.27,26.16 h -17.46 z m 0,-1.08 v -1.14 l -1.92,5.73 h -3.63 l 8.25,-23.91 q 0.06,-0.18 0.27,-0.3 0.24,-0.15 0.45,-0.15 0.21,0 0.45,0.15 0.24,0.12 0.3,0.3 l 6.84,19.32 z m 3.42,-11.13 -2.4,7.56 h 4.89 z"
id="path2" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -255,6 +255,13 @@ namespace FullscreenUI
static bool s_was_paused_on_quick_menu_open = false;
static bool s_about_window_open = false;
// achievements login dialog state
static bool s_achievements_login_open = false;
static bool s_achievements_login_logging_in = false;
static char s_achievements_login_username[256] = {};
static char s_achievements_login_password[256] = {};
static Achievements::LoginRequestReason s_achievements_login_reason = Achievements::LoginRequestReason::UserInitiated;
// local copies of the currently-running game
static std::string s_current_game_title;
static std::string s_current_game_subtitle;
@ -493,6 +500,7 @@ namespace FullscreenUI
//////////////////////////////////////////////////////////////////////////
static void SwitchToAchievementsWindow();
static void SwitchToLeaderboardsWindow();
static void DrawAchievementsLoginWindow();
} // namespace FullscreenUI
//////////////////////////////////////////////////////////////////////////
@ -1034,6 +1042,9 @@ void FullscreenUI::Render()
if (s_about_window_open)
DrawAboutWindow();
if (s_achievements_login_open)
DrawAchievementsLoginWindow();
if (s_input_binding_type != InputBindingInfo::Type::Unknown)
DrawInputBindingWindow();
@ -7207,6 +7218,229 @@ bool FullscreenUI::OpenAchievementsWindow()
return true;
}
void FullscreenUI::DrawAchievementsLoginWindow()
{
ImGui::SetNextWindowSize(LayoutScale(400.0f, 330.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(12.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(24.0f, 24.0f));
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.13f, 0.13f, 0.13f, 0.95f));
if (ImGui::BeginPopupModal("RetroAchievements", &s_achievements_login_open, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar))
{
const float content_width = ImGui::GetContentRegionAvail().x;
ImGui::PushFont(g_large_font);
const float icon_height = LayoutScale(24.0f);
const float icon_width = icon_height * (500.0f / 275.0f);
GSTexture* ra_icon = GetCachedSvgTextureAsync("icons/ra-icon.svg", ImVec2(icon_width, icon_height));
const float title_width = ImGui::CalcTextSize("RetroAchievements").x;
const float header_width = (ra_icon ? icon_width + LayoutScale(10.0f) : 0.0f) + title_width;
const float header_start = (content_width - header_width) * 0.5f;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + header_start);
if (ra_icon)
{
ImGui::Image(reinterpret_cast<ImTextureID>(ra_icon->GetNativeHandle()),
ImVec2(icon_width, icon_height));
ImGui::SameLine();
}
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(1.0f));
ImGui::TextUnformatted(FSUI_CSTR("RetroAchievements"));
ImGui::PopFont();
ImGui::Spacing();
ImGui::Spacing();
ImGui::PushTextWrapPos(content_width);
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
ImGui::TextWrapped(FSUI_CSTR("Please enter your user name and password for retroachievements.org below. Your password will not be saved in PCSX2, an access token will be generated and used instead."));
ImGui::PopStyleColor();
ImGui::PopTextWrapPos();
ImGui::Spacing();
ImGui::Spacing();
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(6.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(12.0f, 10.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
if (s_achievements_login_logging_in)
ImGui::BeginDisabled();
ImGui::SetNextItemWidth(content_width);
ImGui::InputTextWithHint("##username", FSUI_CSTR("Username"), s_achievements_login_username, sizeof(s_achievements_login_username));
ImGui::Spacing();
ImGui::SetNextItemWidth(content_width);
ImGui::InputTextWithHint("##password", FSUI_CSTR("Password"), s_achievements_login_password, sizeof(s_achievements_login_password), ImGuiInputTextFlags_Password);
ImGui::PopStyleColor(3);
ImGui::PopStyleVar(2);
if (s_achievements_login_logging_in)
ImGui::EndDisabled();
ImGui::Spacing();
ImGui::Spacing();
if (s_achievements_login_logging_in)
{
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f));
const float status_width = ImGui::CalcTextSize("Logging in...").x;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (content_width - status_width) * 0.5f);
ImGui::TextUnformatted(FSUI_CSTR("Logging in..."));
ImGui::PopStyleColor();
ImGui::Spacing();
}
const float button_height = LayoutScale(36.0f);
const float button_width = LayoutScale(100.0f);
const float button_spacing = LayoutScale(12.0f);
const float total_width = (button_width * 2) + button_spacing;
const float start_x = (content_width - total_width) * 0.5f;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + start_x);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(6.0f));
const bool can_login = !s_achievements_login_logging_in &&
strlen(s_achievements_login_username) > 0 &&
strlen(s_achievements_login_password) > 0;
if (can_login)
{
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.5f, 0.9f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.6f, 1.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.1f, 0.4f, 0.8f, 1.0f));
}
else
{
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
}
if (ImGui::Button(FSUI_CSTR("Login"), ImVec2(button_width, button_height)) && can_login)
{
s_achievements_login_logging_in = true;
Host::RunOnCPUThread([username = std::string(s_achievements_login_username),
password = std::string(s_achievements_login_password)]() {
Error error;
const bool result = Achievements::Login(username.c_str(), password.c_str(), &error);
s_achievements_login_logging_in = false;
if (!result)
{
ShowToast(std::string(), fmt::format(FSUI_FSTR("Login failed.\nError: {}\n\nPlease check your username and password, and try again."),
error.GetDescription()));
return;
}
ImGui::CloseCurrentPopup();
s_achievements_login_open = false;
s_achievements_login_username[0] = '\0';
s_achievements_login_password[0] = '\0';
if (s_achievements_login_reason == Achievements::LoginRequestReason::UserInitiated)
{
if (!Host::GetBaseBoolSettingValue("Achievements", "Enabled", false))
{
OpenConfirmMessageDialog(FSUI_STR("Enable Achievements"),
FSUI_STR("Achievement tracking is not currently enabled. Your login will have no effect until "
"after tracking is enabled.\n\nDo you want to enable tracking now?"),
[](bool result) {
if (result)
{
Host::SetBaseBoolSettingValue("Achievements", "Enabled", true);
Host::CommitBaseSettingChanges();
VMManager::ApplySettings();
}
});
}
if (!Host::GetBaseBoolSettingValue("Achievements", "ChallengeMode", false))
{
OpenConfirmMessageDialog(FSUI_STR("Enable Hardcore Mode"),
FSUI_STR("Hardcore mode is not currently enabled. Enabling hardcore mode allows you to set times, scores, and "
"participate in game-specific leaderboards.\n\nHowever, hardcore mode also prevents the usage of save "
"states, cheats and slowdown functionality.\n\nDo you want to enable hardcore mode?"),
[](bool result) {
if (result)
{
Host::SetBaseBoolSettingValue("Achievements", "ChallengeMode", true);
Host::CommitBaseSettingChanges();
VMManager::ApplySettings();
bool has_active_game;
{
auto lock = Achievements::GetLock();
has_active_game = Achievements::HasActiveGame();
}
if (has_active_game)
{
OpenConfirmMessageDialog(FSUI_STR("Reset System"),
FSUI_STR("Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?"),
[](bool reset) {
if (reset && VMManager::HasValidVM())
RequestReset();
});
}
}
});
}
}
});
}
ImGui::PopStyleColor(3);
ImGui::SameLine(0, button_spacing);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.4f, 0.4f, 0.4f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
if (ImGui::Button(FSUI_CSTR("Cancel"), ImVec2(button_width, button_height)) && !s_achievements_login_logging_in)
{
if (s_achievements_login_reason == Achievements::LoginRequestReason::TokenInvalid)
{
if (VMManager::HasValidVM() && !Achievements::HasActiveGame())
Achievements::DisableHardcoreMode();
}
ImGui::CloseCurrentPopup();
s_achievements_login_open = false;
s_achievements_login_logging_in = false;
s_achievements_login_username[0] = '\0';
s_achievements_login_password[0] = '\0';
}
ImGui::PopStyleColor(3);
ImGui::PopStyleVar();
ImGui::EndPopup();
}
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
if (!ImGui::IsPopupOpen("RetroAchievements"))
ImGui::OpenPopup("RetroAchievements");
}
bool FullscreenUI::IsAchievementsWindowOpen()
{
return (s_current_main_window == MainWindowType::Achievements);
@ -7414,7 +7648,10 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
ActiveButton(FSUI_ICONSTR(ICON_FA_USER, "Not Logged In"), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
if (MenuButton(FSUI_ICONSTR(ICON_FA_KEY, "Login"), FSUI_CSTR("Logs in to RetroAchievements.")))
Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason::UserInitiated);
{
s_achievements_login_reason = Achievements::LoginRequestReason::UserInitiated;
s_achievements_login_open = true;
}
}
MenuHeading(FSUI_CSTR("Current Game"));
@ -8363,5 +8600,13 @@ TRANSLATE_NOOP("FullscreenUI", "Game not loaded or no RetroAchievements availabl
TRANSLATE_NOOP("FullscreenUI", "Card Enabled");
TRANSLATE_NOOP("FullscreenUI", "Card Name");
TRANSLATE_NOOP("FullscreenUI", "Eject Card");
TRANSLATE_NOOP("FullscreenUI", "Username");
TRANSLATE_NOOP("FullscreenUI", "Password");
TRANSLATE_NOOP("FullscreenUI", "Please enter your user name and password for retroachievements.org below. Your password will not be saved in PCSX2, an access token will be generated and used instead.");
TRANSLATE_NOOP("FullscreenUI", "Login failed.\nError: {}\n\nPlease check your username and password, and try again.");
TRANSLATE_NOOP("FullscreenUI", "Achievement tracking is not currently enabled. Your login will have no effect until after tracking is enabled.\n\nDo you want to enable tracking now?");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode is not currently enabled. Enabling hardcore mode allows you to set times, scores, and participate in game-specific leaderboards.\n\nHowever, hardcore mode also prevents the usage of save states, cheats and slowdown functionality.\n\nDo you want to enable hardcore mode?");
TRANSLATE_NOOP("FullscreenUI", "Logging in...");
// TRANSLATION-STRING-AREA-END
#endif