2023-06-15 11:40:37 +00:00
# include "UI/RetroAchievementScreens.h"
2023-06-30 15:15:49 +00:00
# include "Common/System/OSD.h"
2023-06-19 21:23:50 +00:00
# include "Common/System/Request.h"
2023-06-16 14:29:44 +00:00
# include "Common/UI/View.h"
# include "Common/UI/ViewGroup.h"
2023-06-17 20:22:59 +00:00
# include "Common/UI/Context.h"
2023-06-16 14:29:44 +00:00
# include "Common/Data/Text/I18n.h"
2023-06-18 13:13:16 +00:00
# include "Common/UI/IconCache.h"
2023-06-15 11:40:37 +00:00
2023-06-19 21:23:50 +00:00
# include "Core/Config.h"
2023-07-02 10:00:13 +00:00
# include "Core/RetroAchievements.h"
2023-06-19 21:23:50 +00:00
2023-06-21 12:32:10 +00:00
void RetroAchievementsListScreen : : CreateTabs ( ) {
2023-06-19 21:47:23 +00:00
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
2023-06-15 11:40:37 +00:00
2023-06-27 09:12:25 +00:00
UI : : LinearLayout * achievements = AddTab ( " Achievements " , ac - > T ( " Achievements " ) ) ;
achievements - > SetSpacing ( 5.0f ) ;
CreateAchievementsTab ( achievements ) ;
2023-06-17 09:41:05 +00:00
2023-06-27 21:31:15 +00:00
UI : : LinearLayout * leaderboards = AddTab ( " Leaderboards " , ac - > T ( " Leaderboards " ) ) ;
leaderboards - > SetSpacing ( 5.0f ) ;
CreateLeaderboardsTab ( leaderboards ) ;
2023-06-17 09:41:05 +00:00
2023-06-27 09:12:25 +00:00
# ifdef _DEBUG
CreateStatisticsTab ( AddTab ( " AchievementsStatistics " , ac - > T ( " Statistics " ) ) ) ;
# endif
}
void RetroAchievementsListScreen : : CreateAchievementsTab ( UI : : ViewGroup * achievements ) {
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
using namespace UI ;
2023-06-19 21:47:23 +00:00
2023-06-27 21:31:15 +00:00
rc_client_achievement_list_t * list = rc_client_create_achievement_list ( Achievements : : GetClient ( ) ,
RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL , RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_LOCK_STATE ) ;
std : : vector < const rc_client_achievement_t * > unlockedAchievements ;
std : : vector < const rc_client_achievement_t * > lockedAchievements ;
std : : vector < const rc_client_achievement_t * > otherAchievements ;
for ( uint32_t i = 0 ; i < list - > num_buckets ; i + + ) {
const rc_client_achievement_bucket_t & bucket = list - > buckets [ i ] ;
for ( uint32_t j = 0 ; j < bucket . num_achievements ; j + + ) {
switch ( bucket . bucket_type ) {
case RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED :
lockedAchievements . push_back ( bucket . achievements [ j ] ) ;
break ;
case RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED :
unlockedAchievements . push_back ( bucket . achievements [ j ] ) ;
break ;
default :
otherAchievements . push_back ( bucket . achievements [ j ] ) ;
break ;
}
}
}
2023-06-17 09:41:05 +00:00
2023-06-21 12:32:10 +00:00
achievements - > Add ( new ItemHeader ( ac - > T ( " Achievements " ) ) ) ;
2023-06-27 12:58:39 +00:00
achievements - > Add ( new GameAchievementSummaryView ( ) ) ;
2023-06-17 09:41:05 +00:00
2023-06-21 12:32:10 +00:00
achievements - > Add ( new ItemHeader ( ac - > T ( " Unlocked achievements " ) ) ) ;
2023-06-27 09:12:25 +00:00
for ( auto & achievement : unlockedAchievements ) {
2023-06-27 21:31:15 +00:00
achievements - > Add ( new AchievementView ( achievement ) ) ;
2023-06-19 21:47:23 +00:00
}
2023-06-21 12:32:10 +00:00
achievements - > Add ( new ItemHeader ( ac - > T ( " Locked achievements " ) ) ) ;
2023-06-27 09:12:25 +00:00
for ( auto & achievement : lockedAchievements ) {
2023-06-27 21:31:15 +00:00
achievements - > Add ( new AchievementView ( achievement ) ) ;
}
achievements - > Add ( new ItemHeader ( ac - > T ( " Other achievements " ) ) ) ;
for ( auto & achievement : otherAchievements ) {
achievements - > Add ( new AchievementView ( achievement ) ) ;
2023-06-17 09:41:05 +00:00
}
2023-06-15 11:40:37 +00:00
}
2023-06-16 14:29:44 +00:00
2023-06-27 09:12:25 +00:00
void RetroAchievementsListScreen : : CreateLeaderboardsTab ( UI : : ViewGroup * viewGroup ) {
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
using namespace UI ;
2023-06-27 12:58:39 +00:00
viewGroup - > Add ( new GameAchievementSummaryView ( ) ) ;
2023-06-27 09:12:25 +00:00
viewGroup - > Add ( new ItemHeader ( ac - > T ( " Leaderboards " ) ) ) ;
2023-06-27 21:31:15 +00:00
std : : vector < rc_client_leaderboard_t * > leaderboards ;
rc_client_leaderboard_list_t * list = rc_client_create_leaderboard_list ( Achievements : : GetClient ( ) , RC_CLIENT_LEADERBOARD_LIST_GROUPING_NONE ) ;
for ( uint32_t i = 0 ; i < list - > num_buckets ; i + + ) {
const rc_client_leaderboard_bucket_t & bucket = list - > buckets [ i ] ;
for ( uint32_t j = 0 ; j < bucket . num_leaderboards ; j + + ) {
leaderboards . push_back ( bucket . leaderboards [ j ] ) ;
}
}
2023-06-27 09:12:25 +00:00
for ( auto & leaderboard : leaderboards ) {
2023-06-27 21:31:15 +00:00
int leaderboardID = leaderboard - > id ;
viewGroup - > Add ( new LeaderboardSummaryView ( leaderboard ) ) - > OnClick . Add ( [ = ] ( UI : : EventParams & e ) - > UI : : EventReturn {
screenManager ( ) - > push ( new RetroAchievementsLeaderboardScreen ( gamePath_ , leaderboardID ) ) ;
return UI : : EVENT_DONE ;
} ) ;
2023-06-27 09:12:25 +00:00
}
}
void RetroAchievementsListScreen : : CreateStatisticsTab ( UI : : ViewGroup * viewGroup ) {
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
using namespace UI ;
Achievements : : Statistics stats = Achievements : : GetStatistics ( ) ;
viewGroup - > Add ( new ItemHeader ( ac - > T ( " Statistics " ) ) ) ;
viewGroup - > Add ( new InfoItem ( ac - > T ( " Bad memory accesses " ) , StringFromFormat ( " %d " , stats . badMemoryAccessCount ) ) ) ;
}
2023-06-27 21:31:15 +00:00
RetroAchievementsLeaderboardScreen : : ~ RetroAchievementsLeaderboardScreen ( ) {
if ( pendingAsyncCall_ ) {
rc_client_abort_async ( Achievements : : GetClient ( ) , pendingAsyncCall_ ) ;
}
Poll ( ) ; // Gets rid of pendingEntryList_.
if ( entryList_ ) {
rc_client_destroy_leaderboard_entry_list ( entryList_ ) ;
}
}
RetroAchievementsLeaderboardScreen : : RetroAchievementsLeaderboardScreen ( const Path & gamePath , int leaderboardID )
: TabbedUIDialogScreenWithGameBackground ( gamePath ) , leaderboardID_ ( leaderboardID ) {
rc_client_begin_fetch_leaderboard_entries ( Achievements : : GetClient ( ) , leaderboardID_ , 0 , 20 , [ ] ( int result , const char * error_message , rc_client_leaderboard_entry_list_t * list , rc_client_t * client , void * userdata ) {
if ( result ! = RC_OK ) {
g_OSD . Show ( OSDType : : MESSAGE_ERROR , error_message , 10.0f ) ;
return ;
}
RetroAchievementsLeaderboardScreen * thiz = ( RetroAchievementsLeaderboardScreen * ) userdata ;
thiz - > pendingEntryList_ = list ;
thiz - > pendingAsyncCall_ = nullptr ;
} , this ) ;
}
2023-06-27 09:12:25 +00:00
void RetroAchievementsLeaderboardScreen : : CreateTabs ( ) {
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
2023-06-27 21:31:15 +00:00
const rc_client_leaderboard_t * leaderboard = rc_client_get_leaderboard_info ( Achievements : : GetClient ( ) , leaderboardID_ ) ;
2023-06-27 09:12:25 +00:00
2023-06-27 21:31:15 +00:00
using namespace UI ;
UI : : LinearLayout * layout = AddTab ( " AchievementsLeaderboard " , leaderboard - > title ) ;
2023-06-27 09:12:25 +00:00
layout - > Add ( new TextView ( leaderboard - > description ) ) ;
layout - > Add ( new ItemHeader ( ac - > T ( " Leaderboard " ) ) ) ;
2023-06-27 21:31:15 +00:00
if ( entryList_ ) {
for ( uint32_t i = 0 ; i < entryList_ - > num_entries ; i + + ) {
bool is_self = ( i = = entryList_ - > user_index ) ;
// Should highlight somehow.
const rc_client_leaderboard_entry_t & entry = entryList_ - > entries [ i ] ;
2023-07-02 15:12:46 +00:00
char buffer [ 512 ] ;
rc_client_leaderboard_entry_get_user_image_url ( & entryList_ - > entries [ i ] , buffer , sizeof ( buffer ) ) ;
2023-06-27 21:31:15 +00:00
// Can also show entry.submitted, which is a time_t. And maybe highlight recent ones?
2023-07-02 15:12:46 +00:00
layout - > Add ( new LeaderboardEntryView ( & entryList_ - > entries [ i ] , is_self ) ) ;
2023-06-27 21:31:15 +00:00
}
2023-06-27 09:12:25 +00:00
}
}
void RetroAchievementsLeaderboardScreen : : Poll ( ) {
2023-06-27 21:31:15 +00:00
if ( pendingEntryList_ ) {
if ( entryList_ ) {
rc_client_destroy_leaderboard_entry_list ( entryList_ ) ;
}
entryList_ = pendingEntryList_ ;
pendingEntryList_ = nullptr ;
2023-06-27 09:12:25 +00:00
RecreateViews ( ) ;
}
}
void RetroAchievementsLeaderboardScreen : : update ( ) {
TabbedUIDialogScreenWithGameBackground : : update ( ) ;
Poll ( ) ;
}
2023-06-27 12:58:39 +00:00
RetroAchievementsSettingsScreen : : ~ RetroAchievementsSettingsScreen ( ) { }
2023-06-16 14:29:44 +00:00
void RetroAchievementsSettingsScreen : : CreateTabs ( ) {
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
2023-06-23 20:08:52 +00:00
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
2023-06-16 14:29:44 +00:00
using namespace UI ;
2023-06-27 07:47:35 +00:00
CreateAccountTab ( AddTab ( " AchievementsAccount " , ac - > T ( " Account " ) ) ) ;
CreateSettingsTab ( AddTab ( " AchievementsSettings " , di - > T ( " Settings " ) ) ) ;
2023-06-16 14:29:44 +00:00
}
void RetroAchievementsSettingsScreen : : sendMessage ( const char * message , const char * value ) {
TabbedUIDialogScreenWithGameBackground : : sendMessage ( message , value ) ;
if ( ! strcmp ( message , " achievements_loginstatechange " ) ) {
RecreateViews ( ) ;
}
}
void RetroAchievementsSettingsScreen : : CreateAccountTab ( UI : : ViewGroup * viewGroup ) {
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
2023-06-21 13:45:07 +00:00
auto di = GetI18NCategory ( I18NCat : : DIALOG ) ;
2023-06-16 14:29:44 +00:00
using namespace UI ;
2023-07-01 10:31:46 +00:00
if ( ! g_Config . bAchievementsEnable ) {
viewGroup - > Add ( new TextView ( ac - > T ( " Achievements are disabled " ) ) ) ;
} else if ( Achievements : : IsLoggedIn ( ) ) {
2023-06-27 21:31:15 +00:00
const rc_client_user_t * info = rc_client_get_user_info ( Achievements : : GetClient ( ) ) ;
// In the future, RetroAchievements will support display names. Prepare for that.
if ( strcmp ( info - > display_name , info - > username ) ! = 0 ) {
viewGroup - > Add ( new InfoItem ( ac - > T ( " Name " ) , info - > display_name ) ) ;
}
viewGroup - > Add ( new InfoItem ( ac - > T ( " Username " ) , info - > username ) ) ;
// viewGroup->Add(new InfoItem(ac->T("Unread messages"), info.numUnreadMessages));
2023-06-23 20:08:52 +00:00
viewGroup - > Add ( new Choice ( di - > T ( " Log out " ) ) ) - > OnClick . Add ( [ = ] ( UI : : EventParams & ) - > UI : : EventReturn {
2023-06-16 14:29:44 +00:00
Achievements : : Logout ( ) ;
return UI : : EVENT_DONE ;
} ) ;
} else {
2023-06-19 21:23:50 +00:00
// TODO: Add UI for platforms that don't support System_AskUsernamePassword.
2023-06-21 13:45:07 +00:00
if ( System_GetPropertyBool ( SYSPROP_HAS_LOGIN_DIALOG ) ) {
2023-06-23 20:08:52 +00:00
viewGroup - > Add ( new Choice ( ac - > T ( " Log in " ) ) ) - > OnClick . Add ( [ = ] ( UI : : EventParams & ) - > UI : : EventReturn {
2023-06-21 13:45:07 +00:00
System_AskUsernamePassword ( ac - > T ( " Log in " ) , [ ] ( const std : : string & value , int ) {
std : : vector < std : : string > parts ;
SplitString ( value , ' \n ' , parts ) ;
if ( parts . size ( ) = = 2 & & ! parts [ 0 ] . empty ( ) & & ! parts [ 1 ] . empty ( ) ) {
Achievements : : LoginAsync ( parts [ 0 ] . c_str ( ) , parts [ 1 ] . c_str ( ) ) ;
}
2023-06-27 09:12:25 +00:00
} ) ;
2023-06-21 13:45:07 +00:00
return UI : : EVENT_DONE ;
} ) ;
} else {
// Hack up a temporary quick login-form-ish-thing
2023-06-23 20:08:52 +00:00
viewGroup - > Add ( new PopupTextInputChoice ( & username_ , di - > T ( " Username " ) , " " , 128 , screenManager ( ) ) ) ;
viewGroup - > Add ( new PopupTextInputChoice ( & password_ , di - > T ( " Password " ) , " " , 128 , screenManager ( ) ) ) ;
viewGroup - > Add ( new Choice ( di - > T ( " Log in " ) ) ) - > OnClick . Add ( [ = ] ( UI : : EventParams & ) - > UI : : EventReturn {
2023-06-21 13:45:07 +00:00
if ( ! username_ . empty ( ) & & ! password_ . empty ( ) ) {
Achievements : : LoginAsync ( username_ . c_str ( ) , password_ . c_str ( ) ) ;
2023-06-19 21:23:50 +00:00
}
2023-06-21 13:45:07 +00:00
return UI : : EVENT_DONE ;
2023-06-19 21:23:50 +00:00
} ) ;
2023-06-21 13:45:07 +00:00
}
2023-06-19 21:23:50 +00:00
viewGroup - > Add ( new Choice ( ac - > T ( " Register on www.retroachievements.org " ) ) ) - > OnClick . Add ( [ & ] ( UI : : EventParams & ) - > UI : : EventReturn {
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://retroachievements.org/createaccount.php " ) ;
2023-06-16 14:29:44 +00:00
return UI : : EVENT_DONE ;
} ) ;
}
2023-06-21 13:45:07 +00:00
viewGroup - > Add ( new ItemHeader ( di - > T ( " Links " ) ) ) ;
viewGroup - > Add ( new Choice ( ac - > T ( " RetroAchievements website " ) ) ) - > OnClick . Add ( [ & ] ( UI : : EventParams & ) - > UI : : EventReturn {
2023-06-19 21:23:50 +00:00
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://www.retroachievements.org/ " ) ;
return UI : : EVENT_DONE ;
} ) ;
2023-06-21 13:45:07 +00:00
viewGroup - > Add ( new Choice ( ac - > T ( " How to use RetroAchievements " ) ) ) - > OnClick . Add ( [ & ] ( UI : : EventParams & ) - > UI : : EventReturn {
System_LaunchUrl ( LaunchUrlType : : BROWSER_URL , " https://www.ppsspp.org/docs/reference/retro-achievements " ) ;
return UI : : EVENT_DONE ;
} ) ;
2023-06-19 21:23:50 +00:00
}
void RetroAchievementsSettingsScreen : : CreateSettingsTab ( UI : : ViewGroup * viewGroup ) {
auto ac = GetI18NCategory ( I18NCat : : ACHIEVEMENTS ) ;
using namespace UI ;
viewGroup - > Add ( new ItemHeader ( ac - > T ( " Settings " ) ) ) ;
2023-07-01 10:31:46 +00:00
viewGroup - > Add ( new CheckBox ( & g_Config . bAchievementsEnable , ac - > T ( " Achievements enabled " ) ) ) - > OnClick . Add ( [ & ] ( UI : : EventParams & e ) - > UI : : EventReturn {
Achievements : : UpdateSettings ( ) ;
RecreateViews ( ) ;
return UI : : EVENT_DONE ;
} ) ;
2023-06-27 12:58:39 +00:00
viewGroup - > Add ( new CheckBox ( & g_Config . bAchievementsChallengeMode , ac - > T ( " Challenge Mode (no savestates) " ) ) ) ;
2023-07-02 22:14:23 +00:00
viewGroup - > Add ( new CheckBox ( & g_Config . bAchievementsEncoreMode , ac - > T ( " Encore Mode " ) ) ) ;
2023-07-01 10:31:46 +00:00
viewGroup - > Add ( new CheckBox ( & g_Config . bAchievementsRichPresence , ac - > T ( " Rich Presence " ) ) ) - > SetEnabledPtr ( & g_Config . bAchievementsEnable ) ;
viewGroup - > Add ( new CheckBox ( & g_Config . bAchievementsSoundEffects , ac - > T ( " Sound Effects " ) ) ) - > SetEnabledPtr ( & g_Config . bAchievementsEnable ) ; // not yet implemented
viewGroup - > Add ( new CheckBox ( & g_Config . bAchievementsLogBadMemReads , ac - > T ( " Log bad memory accesses " ) ) ) - > SetEnabledPtr ( & g_Config . bAchievementsEnable ) ;
2023-06-19 21:23:50 +00:00
// TODO: What are these for?
// viewGroup->Add(new CheckBox(&g_Config.bAchievementsTestMode, ac->T("Test Mode")));
// viewGroup->Add(new CheckBox(&g_Config.bAchievementsUnofficialTestMode, ac->T("Unofficial Test Mode")));
2023-06-16 14:29:44 +00:00
}
2023-06-17 20:22:59 +00:00
2023-06-27 21:31:15 +00:00
void MeasureAchievement ( const UIContext & dc , const rc_client_achievement_t * achievement , AchievementRenderStyle style , float * w , float * h ) {
2023-06-17 20:22:59 +00:00
* w = 0.0f ;
2023-06-27 21:31:15 +00:00
switch ( style ) {
case AchievementRenderStyle : : PROGRESS_INDICATOR :
* h = 36.0f ;
break ;
default :
* h = 72.0f ;
break ;
}
2023-06-17 20:22:59 +00:00
}
2023-06-27 12:58:39 +00:00
void MeasureGameAchievementSummary ( const UIContext & dc , float * w , float * h ) {
2023-06-19 21:47:23 +00:00
* w = 0.0f ;
2023-06-21 12:32:10 +00:00
* h = 72.0f ;
2023-06-27 12:58:39 +00:00
if ( Achievements : : ChallengeModeActive ( ) ) {
* h + = 20.0f ;
}
2023-06-19 21:47:23 +00:00
}
2023-06-27 21:31:15 +00:00
void MeasureLeaderboardSummary ( const UIContext & dc , const rc_client_leaderboard_t * leaderboard , float * w , float * h ) {
2023-06-27 09:12:25 +00:00
* w = 0.0f ;
* h = 72.0f ;
}
2023-07-02 15:12:46 +00:00
void MeasureLeaderboardEntry ( const UIContext & dc , const rc_client_leaderboard_entry_t * entry , float * w , float * h ) {
* w = 0.0f ;
* h = 72.0f ;
}
2023-06-17 20:22:59 +00:00
// Graphical
2023-06-27 21:31:15 +00:00
void RenderAchievement ( UIContext & dc , const rc_client_achievement_t * achievement , AchievementRenderStyle style , const Bounds & bounds , float alpha , float startTime , float time_s ) {
2023-06-17 20:22:59 +00:00
using namespace UI ;
2023-06-26 08:13:18 +00:00
UI : : Drawable background = UI : : Drawable ( dc . theme - > backgroundColor ) ;
2023-06-27 21:31:15 +00:00
if ( ! achievement - > unlocked ) {
// Make the background color gray.
// TODO: Different colors in challenge mode, or even in the "re-take achievements" mode when we add that?
2023-06-21 12:32:10 +00:00
background . color = 0x706060 ;
}
2023-06-21 10:17:44 +00:00
background . color = colorAlpha ( background . color , alpha ) ;
2023-06-22 07:27:58 +00:00
uint32_t fgColor = colorAlpha ( dc . theme - > itemStyle . fgColor , alpha ) ;
2023-06-17 20:22:59 +00:00
2023-06-21 12:32:10 +00:00
if ( style = = AchievementRenderStyle : : UNLOCKED ) {
float mixWhite = pow ( Clamp ( ( float ) ( 1.0f - ( time_s - startTime ) ) , 0.0f , 1.0f ) , 3.0f ) ;
background . color = colorBlend ( 0xFFE0FFFF , background . color , mixWhite ) ;
}
2023-06-18 13:13:16 +00:00
float iconSpace = 64.0f ;
2023-06-20 07:18:47 +00:00
dc . Flush ( ) ;
2023-06-18 13:13:16 +00:00
2023-06-17 20:22:59 +00:00
dc . Begin ( ) ;
dc . FillRect ( background , bounds ) ;
2023-06-21 12:32:10 +00:00
dc . SetFontStyle ( dc . theme - > uiFont ) ;
2023-06-19 21:47:23 +00:00
dc . SetFontScale ( 1.0f , 1.0f ) ;
2023-06-27 21:31:15 +00:00
dc . DrawTextRect ( achievement - > title , bounds . Inset ( iconSpace + 12.0f , 2.0f , 5.0f , 5.0f ) , fgColor , ALIGN_TOPLEFT ) ;
2023-06-17 20:22:59 +00:00
2023-06-19 21:47:23 +00:00
dc . SetFontScale ( 0.66f , 0.66f ) ;
2023-06-27 21:31:15 +00:00
dc . DrawTextRect ( achievement - > description , bounds . Inset ( iconSpace + 12.0f , 39.0f , 5.0f , 5.0f ) , fgColor , ALIGN_TOPLEFT ) ;
2023-06-17 20:22:59 +00:00
2023-06-27 21:31:15 +00:00
// TODO: Draw measured_progress / measured_percent in a cute way
char temp [ 512 ] ;
snprintf ( temp , sizeof ( temp ) , " %d " , achievement - > points ) ;
2023-06-17 20:22:59 +00:00
dc . SetFontScale ( 1.5f , 1.5f ) ;
2023-06-22 07:27:58 +00:00
dc . DrawTextRect ( temp , bounds . Expand ( - 5.0f , - 5.0f ) , fgColor , ALIGN_RIGHT | ALIGN_VCENTER ) ;
2023-06-17 20:22:59 +00:00
dc . SetFontScale ( 1.0f , 1.0f ) ;
2023-06-18 13:13:16 +00:00
dc . Flush ( ) ;
2023-06-27 21:31:15 +00:00
// Download and display the image.
if ( RC_OK = = rc_client_achievement_get_image_url ( achievement , achievement - > state , temp , sizeof ( temp ) ) ) {
Achievements : : DownloadImageIfMissing ( achievement - > badge_name , std : : move ( std : : string ( temp ) ) ) ;
if ( g_iconCache . BindIconTexture ( & dc , achievement - > badge_name ) ) {
dc . Draw ( ) - > DrawTexRect ( Bounds ( bounds . x + 4.0f , bounds . y + 4.0f , iconSpace , iconSpace ) , 0.0f , 0.0f , 1.0f , 1.0f , whiteAlpha ( alpha ) ) ;
}
2023-06-18 13:13:16 +00:00
}
dc . Flush ( ) ;
dc . RebindTexture ( ) ;
2023-06-17 20:22:59 +00:00
}
2023-06-27 12:58:39 +00:00
void RenderGameAchievementSummary ( UIContext & dc , const Bounds & bounds , float alpha ) {
2023-06-19 21:47:23 +00:00
using namespace UI ;
UI : : Drawable background = dc . theme - > itemStyle . background ;
2023-06-27 12:58:39 +00:00
background . color = alphaMul ( background . color , alpha ) ;
2023-06-22 07:27:58 +00:00
uint32_t fgColor = colorAlpha ( dc . theme - > itemStyle . fgColor , alpha ) ;
2023-06-19 21:47:23 +00:00
float iconSpace = 64.0f ;
2023-06-20 07:18:47 +00:00
dc . Flush ( ) ;
2023-06-19 21:47:23 +00:00
dc . Begin ( ) ;
dc . FillRect ( background , bounds ) ;
2023-06-21 12:32:10 +00:00
dc . SetFontStyle ( dc . theme - > uiFont ) ;
2023-06-27 21:31:15 +00:00
const rc_client_game_t * gameInfo = rc_client_get_game_info ( Achievements : : GetClient ( ) ) ;
2023-06-19 21:47:23 +00:00
dc . SetFontScale ( 1.0f , 1.0f ) ;
2023-06-27 21:31:15 +00:00
dc . DrawTextRect ( gameInfo - > title , bounds . Inset ( iconSpace + 5.0f , 2.0f , 5.0f , 5.0f ) , fgColor , ALIGN_TOPLEFT ) ;
2023-06-19 21:47:23 +00:00
std : : string description = Achievements : : GetGameAchievementSummary ( ) ;
dc . SetFontScale ( 0.66f , 0.66f ) ;
2023-06-22 07:27:58 +00:00
dc . DrawTextRect ( description . c_str ( ) , bounds . Inset ( iconSpace + 5.0f , 38.0f , 5.0f , 5.0f ) , fgColor , ALIGN_TOPLEFT ) ;
2023-06-19 21:47:23 +00:00
dc . SetFontScale ( 1.0f , 1.0f ) ;
dc . Flush ( ) ;
2023-06-27 21:31:15 +00:00
char temp [ 512 ] ;
if ( RC_OK = = rc_client_game_get_image_url ( gameInfo , temp , sizeof ( temp ) ) ) {
Achievements : : DownloadImageIfMissing ( gameInfo - > badge_name , std : : move ( std : : string ( temp ) ) ) ;
if ( g_iconCache . BindIconTexture ( & dc , gameInfo - > badge_name ) ) {
dc . Draw ( ) - > DrawTexRect ( Bounds ( bounds . x , bounds . y , iconSpace , iconSpace ) , 0.0f , 0.0f , 1.0f , 1.0f , whiteAlpha ( alpha ) ) ;
}
2023-06-19 21:47:23 +00:00
}
dc . Flush ( ) ;
dc . RebindTexture ( ) ;
}
2023-06-27 21:31:15 +00:00
void RenderLeaderboardSummary ( UIContext & dc , const rc_client_leaderboard_t * leaderboard , AchievementRenderStyle style , const Bounds & bounds , float alpha , float startTime , float time_s ) {
2023-06-27 09:12:25 +00:00
using namespace UI ;
UI : : Drawable background = UI : : Drawable ( dc . theme - > backgroundColor ) ;
background . color = colorAlpha ( background . color , alpha ) ;
uint32_t fgColor = colorAlpha ( dc . theme - > itemStyle . fgColor , alpha ) ;
if ( style = = AchievementRenderStyle : : UNLOCKED ) {
float mixWhite = pow ( Clamp ( ( float ) ( 1.0f - ( time_s - startTime ) ) , 0.0f , 1.0f ) , 3.0f ) ;
background . color = colorBlend ( 0xFFE0FFFF , background . color , mixWhite ) ;
}
dc . Flush ( ) ;
dc . Begin ( ) ;
dc . FillRect ( background , bounds ) ;
dc . SetFontStyle ( dc . theme - > uiFont ) ;
dc . SetFontScale ( 1.0f , 1.0f ) ;
2023-06-27 21:31:15 +00:00
dc . DrawTextRect ( leaderboard - > title , bounds . Inset ( 12.0f , 2.0f , 5.0f , 5.0f ) , fgColor , ALIGN_TOPLEFT ) ;
2023-06-27 09:12:25 +00:00
dc . SetFontScale ( 0.66f , 0.66f ) ;
2023-06-27 21:31:15 +00:00
dc . DrawTextRect ( leaderboard - > description , bounds . Inset ( 12.0f , 39.0f , 5.0f , 5.0f ) , fgColor , ALIGN_TOPLEFT ) ;
2023-06-27 09:12:25 +00:00
/*
char temp [ 64 ] ;
snprintf ( temp , sizeof ( temp ) , " %d " , leaderboard . points ) ;
dc . SetFontScale ( 1.5f , 1.5f ) ;
dc . DrawTextRect ( temp , bounds . Expand ( - 5.0f , - 5.0f ) , fgColor , ALIGN_RIGHT | ALIGN_VCENTER ) ;
dc . SetFontScale ( 1.0f , 1.0f ) ;
dc . Flush ( ) ;
*/
dc . Flush ( ) ;
dc . RebindTexture ( ) ;
}
2023-06-19 21:47:23 +00:00
2023-07-02 15:12:46 +00:00
void RenderLeaderboardEntry ( UIContext & dc , const rc_client_leaderboard_entry_t * entry , const Bounds & bounds , float alpha ) {
using namespace UI ;
UI : : Drawable background = dc . theme - > itemStyle . background ;
background . color = alphaMul ( background . color , alpha ) ;
uint32_t fgColor = alphaMul ( dc . theme - > itemStyle . fgColor , alpha ) ;
float iconSize = 64.0f ;
float numberSpace = 128.0f ;
float iconLeft = numberSpace + 5.0f ;
float iconSpace = numberSpace + 5.0f + iconSize ;
dc . Flush ( ) ;
dc . Begin ( ) ;
dc . FillRect ( background , bounds ) ;
dc . SetFontStyle ( dc . theme - > uiFont ) ;
dc . SetFontScale ( 1.5f , 1.5f ) ;
dc . DrawTextRect ( StringFromFormat ( " %d " , entry - > rank ) . c_str ( ) , Bounds ( bounds . x + 4.0f , bounds . y + 4.0f , numberSpace - 10.0f , bounds . h - 4.0f * 2.0f ) , fgColor , ALIGN_TOPRIGHT ) ;
dc . SetFontScale ( 1.0f , 1.0f ) ;
dc . DrawTextRect ( entry - > user , bounds . Inset ( iconSpace + 5.0f , 2.0f , 5.0f , 5.0f ) , fgColor , ALIGN_TOPLEFT ) ;
dc . SetFontScale ( 0.66f , 0.66f ) ;
dc . DrawTextRect ( entry - > display , bounds . Inset ( iconSpace + 5.0f , 38.0f , 5.0f , 5.0f ) , fgColor , ALIGN_TOPLEFT ) ;
dc . SetFontScale ( 1.0f , 1.0f ) ;
dc . Flush ( ) ;
// Come up with a unique name for the icon entry.
char entryName [ 256 ] ;
snprintf ( entryName , sizeof ( entryName ) , " lbe:%s " , entry - > user ) ;
char temp [ 512 ] ;
if ( RC_OK = = rc_client_leaderboard_entry_get_user_image_url ( entry , temp , sizeof ( temp ) ) ) {
Achievements : : DownloadImageIfMissing ( entryName , std : : move ( std : : string ( temp ) ) ) ;
if ( g_iconCache . BindIconTexture ( & dc , entryName ) ) {
dc . Draw ( ) - > DrawTexRect ( Bounds ( bounds . x + iconLeft , bounds . y + 4.0f , 64.0f , 64.0f ) , 0.0f , 0.0f , 1.0f , 1.0f , whiteAlpha ( alpha ) ) ;
}
}
dc . Flush ( ) ;
dc . RebindTexture ( ) ;
}
2023-06-17 20:22:59 +00:00
void AchievementView : : Draw ( UIContext & dc ) {
2023-06-26 08:13:18 +00:00
RenderAchievement ( dc , achievement_ , AchievementRenderStyle : : LISTED , bounds_ , 1.0f , 0.0f , 0.0f ) ;
2023-06-17 20:22:59 +00:00
}
void AchievementView : : GetContentDimensions ( const UIContext & dc , float & w , float & h ) const {
2023-06-27 21:31:15 +00:00
MeasureAchievement ( dc , achievement_ , AchievementRenderStyle : : LISTED , & w , & h ) ;
2023-06-21 10:17:44 +00:00
}
void AchievementView : : Click ( ) {
// In debug builds, clicking achievements will show them being unlocked (which may be a lie).
# ifdef _DEBUG
2023-06-27 21:31:15 +00:00
g_OSD . ShowAchievementUnlocked ( achievement_ - > id ) ;
2023-06-21 10:17:44 +00:00
# endif
2023-06-17 20:22:59 +00:00
}
2023-06-19 21:47:23 +00:00
2023-07-02 15:12:46 +00:00
void GameAchievementSummaryView : : Draw ( UIContext & dc ) {
2023-06-27 12:58:39 +00:00
RenderGameAchievementSummary ( dc , bounds_ , 1.0f ) ;
2023-07-02 15:12:46 +00:00
}
void GameAchievementSummaryView : : GetContentDimensions ( const UIContext & dc , float & w , float & h ) const {
2023-06-27 12:58:39 +00:00
MeasureGameAchievementSummary ( dc , & w , & h ) ;
2023-07-02 15:12:46 +00:00
}
2023-06-27 09:12:25 +00:00
void LeaderboardSummaryView : : Draw ( UIContext & dc ) {
RenderLeaderboardSummary ( dc , leaderboard_ , AchievementRenderStyle : : LISTED , bounds_ , 1.0f , 0.0f , 0.0f ) ;
}
void LeaderboardSummaryView : : GetContentDimensions ( const UIContext & dc , float & w , float & h ) const {
MeasureLeaderboardSummary ( dc , leaderboard_ , & w , & h ) ;
}
2023-07-02 15:12:46 +00:00
void LeaderboardEntryView : : Draw ( UIContext & dc ) {
RenderLeaderboardEntry ( dc , entry_ , bounds_ , 1.0f ) ;
2023-06-19 21:47:23 +00:00
}
2023-07-02 15:12:46 +00:00
void LeaderboardEntryView : : GetContentDimensions ( const UIContext & dc , float & w , float & h ) const {
MeasureLeaderboardEntry ( dc , entry_ , & w , & h ) ;
2023-06-19 21:47:23 +00:00
}
2023-07-02 15:12:46 +00:00