@@ -1086,14 +1086,6 @@ void FullscreenUI::DrawAchievementsWindow()
10861086 }
10871087 EndFullscreenWindow ();
10881088
1089- SetFullscreenStatusText (std::array{
1090- std::make_pair (ICON_PF_ACHIEVEMENTS_MISSABLE, TRANSLATE_SV (" Achievements" , " Missable" )),
1091- std::make_pair (ICON_PF_ACHIEVEMENTS_PROGRESSION, TRANSLATE_SV (" Achievements" , " Progression" )),
1092- std::make_pair (ICON_PF_ACHIEVEMENTS_WIN, TRANSLATE_SV (" Achievements" , " Win Condition" )),
1093- std::make_pair (ICON_FA_LOCK, TRANSLATE_SV (" Achievements" , " Locked" )),
1094- std::make_pair (ICON_FA_UNLOCK, TRANSLATE_SV (" Achievements" , " Unlocked" )),
1095- });
1096-
10971089 if (IsGamepadInputSource ())
10981090 {
10991091 if (s_achievements_locals.open_subset )
@@ -1137,159 +1129,197 @@ void FullscreenUI::DrawAchievementsWindow()
11371129
11381130void FullscreenUI::DrawAchievement (const rc_client_achievement_t * cheevo)
11391131{
1140- static constexpr float progress_height_unscaled = 20 .0f ;
1141- static constexpr float progress_spacing_unscaled = 5 .0f ;
1142- static constexpr float progress_rounding_unscaled = 5 .0f ;
1132+ static constexpr const float progress_height_unscaled = 20 .0f ;
1133+ static constexpr const float progress_rounding_unscaled = 5 .0f ;
1134+
1135+ static constexpr const float & title_font_size = UIStyle.LargeFontSize ;
1136+ static constexpr const float & title_font_weight = UIStyle.BoldFontWeight ;
1137+ static constexpr const float & subtitle_font_size = UIStyle.MediumFontSize ;
1138+ static constexpr const float & subtitle_font_weight = UIStyle.NormalFontWeight ;
1139+ static constexpr const float & type_badge_font_size = UIStyle.MediumSmallFontSize ;
1140+ static constexpr const float & type_badge_font_weight = UIStyle.BoldFontWeight ;
1141+
1142+ const std::string_view title (cheevo->title );
1143+ const std::string_view description = cheevo->description ? std::string_view (cheevo->description ) : std::string_view ();
1144+ const std::string_view measured_progress (cheevo->measured_progress );
1145+ const bool is_unlocked = (cheevo->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED);
1146+ const bool is_measured = (!is_unlocked && !measured_progress.empty ());
1147+
1148+ ImVec2 type_badge_padding;
1149+ ImVec2 type_badge_size;
1150+ float type_badge_spacing = 0 .0f ;
1151+ float type_badge_rounding = 0 .0f ;
1152+ ImU32 type_badge_bg_color = 0 ;
1153+ TinyString type_badge_text;
1154+ switch (cheevo->type )
1155+ {
1156+ case RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE:
1157+ type_badge_text.format (ICON_PF_ACHIEVEMENTS_MISSABLE " {}" , TRANSLATE_SV (" Achievements" , " Missable" ));
1158+ type_badge_bg_color = IM_COL32 (205 , 45 , 32 , 255 );
1159+ break ;
11431160
1144- const float spacing = LayoutScale (LAYOUT_MENU_ITEM_TITLE_SUMMARY_SPACING);
1145- const u32 text_color = ImGui::GetColorU32 (UIStyle.SecondaryTextColor );
1146- const u32 summary_color = ImGui::GetColorU32 (DarkerColor (UIStyle.SecondaryTextColor ));
1147- const u32 rarity_color = ImGui::GetColorU32 (DarkerColor (DarkerColor (UIStyle.SecondaryTextColor )));
1161+ case RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION:
1162+ type_badge_text.format (ICON_PF_ACHIEVEMENTS_PROGRESSION " {}" , TRANSLATE_SV (" Achievements" , " Progression" ));
1163+ type_badge_bg_color = IM_COL32 (13 , 71 , 161 , 255 );
1164+ break ;
1165+
1166+ case RC_CLIENT_ACHIEVEMENT_TYPE_WIN:
1167+ type_badge_text.format (ICON_PF_ACHIEVEMENTS_PROGRESSION " {}" , TRANSLATE_SV (" Achievements" , " Win Condition" ));
1168+ type_badge_bg_color = IM_COL32 (50 , 110 , 30 , 255 );
1169+ break ;
1170+ }
1171+ if (!type_badge_text.empty ())
1172+ {
1173+ type_badge_padding = LayoutScale (5 .0f , 3 .0f );
1174+ type_badge_spacing = LayoutScale (10 .0f );
1175+ type_badge_rounding = LayoutScale (3 .0f );
1176+ type_badge_size = UIStyle.Font ->CalcTextSizeA (type_badge_font_size, type_badge_font_weight, FLT_MAX, 0 .0f ,
1177+ IMSTR_START_END (type_badge_text));
1178+ type_badge_size += type_badge_padding * 2 .0f ;
1179+ }
11481180
11491181 const ImVec2 image_size = LayoutScale (50 .0f , 50 .0f );
1150- const bool is_unlocked = (cheevo->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED);
1151- const std::string_view measured_progress (cheevo->measured_progress );
1152- const bool is_measured = !is_unlocked && !measured_progress.empty ();
1153- const float unlock_rarity_height = spacing + UIStyle.MediumFontSize ;
1154- const ImVec2 points_template_size = UIStyle.Font ->CalcTextSizeA (
1155- UIStyle.MediumFontSize , UIStyle.NormalFontWeight , FLT_MAX, 0 .0f , TRANSLATE (" Achievements" , " XXX points" ));
1182+ const float image_right_padding = LayoutScale (15 .0f );
11561183 const float avail_width = GetMenuButtonAvailableWidth ();
1157- const size_t summary_length = std::strlen (cheevo->description );
1158- const float summary_wrap_width = (avail_width - (image_size.x + spacing + spacing) - points_template_size.x );
1159- const ImVec2 summary_text_size =
1160- UIStyle.Font ->CalcTextSizeA (UIStyle.MediumFontSize , UIStyle.NormalFontWeight , FLT_MAX, summary_wrap_width,
1161- cheevo->description , cheevo->description + summary_length);
1162-
1163- const float content_height = UIStyle.LargeFontSize + spacing + summary_text_size.y + unlock_rarity_height +
1164- LayoutScale (is_measured ? progress_height_unscaled : 0 .0f ) +
1184+ const float spacing = LayoutScale (4 .0f );
1185+ const ImVec2 right_side_size = UIStyle.Font ->CalcTextSizeA (UIStyle.MediumFontSize , UIStyle.NormalFontWeight , FLT_MAX,
1186+ 0 .0f , TRANSLATE (" Achievements" , " XXX points" ));
1187+ const float max_text_width = avail_width - (image_size.x + image_right_padding + spacing + right_side_size.x );
1188+ const float max_title_width =
1189+ max_text_width - (type_badge_text.empty () ? 0 .0f : type_badge_size.x + type_badge_spacing);
1190+ const ImVec2 title_size = UIStyle.Font ->CalcTextSizeA (UIStyle.LargeFontSize , UIStyle.BoldFontWeight , FLT_MAX,
1191+ max_title_width, IMSTR_START_END (title));
1192+ const ImVec2 description_size = description.empty () ?
1193+ ImVec2 () :
1194+ UIStyle.Font ->CalcTextSizeA (UIStyle.MediumFontSize , UIStyle.NormalFontWeight ,
1195+ FLT_MAX, max_text_width, IMSTR_START_END (description));
1196+ const float content_height = (title_size.y + spacing + description_size.y + spacing + UIStyle.MediumFontSize ) +
1197+ (is_measured ? (spacing + LayoutScale (progress_height_unscaled)) : 0 .0f ) +
11651198 LayoutScale (LAYOUT_MENU_ITEM_EXTRA_HEIGHT);
1199+
1200+ SmallString text;
1201+ text.format (" chv_{}" , cheevo->id );
1202+
11661203 ImRect bb;
11671204 bool visible, hovered;
1168- const bool clicked =
1169- MenuButtonFrame (TinyString::from_format (" chv_{}" , cheevo->id ), content_height, true , &bb, &visible, &hovered);
1205+ const bool clicked = MenuButtonFrame (text, content_height, true , &bb, &visible, &hovered);
11701206 if (!visible)
11711207 return ;
11721208
1173- const std::string& badge_path =
1174- GetCachedAchievementBadgePath (cheevo, cheevo->state != RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED);
1209+ ImDrawList* const dl = ImGui::GetWindowDrawList ();
11751210
1176- if (!badge_path.empty ())
1211+ if (const std::string& badge_path = GetCachedAchievementBadgePath (cheevo, !is_unlocked); !badge_path.empty ())
11771212 {
11781213 GPUTexture* badge = GetCachedTextureAsync (badge_path);
11791214 if (badge)
11801215 {
11811216 const ImRect image_bb = CenterImage (ImRect (bb.Min , bb.Min + image_size), badge);
1182- ImGui::GetWindowDrawList () ->AddImage (badge, image_bb.Min , image_bb.Max , ImVec2 (0 .0f , 0 .0f ), ImVec2 (1 .0f , 1 .0f ),
1183- IM_COL32 (255 , 255 , 255 , 255 ));
1217+ dl ->AddImage (badge, image_bb.Min , image_bb.Max , ImVec2 (0 .0f , 0 .0f ), ImVec2 (1 .0f , 1 .0f ),
1218+ IM_COL32 (255 , 255 , 255 , 255 ));
11841219 }
11851220 }
11861221
1187- SmallString text;
1222+ // make it easier to compute bounding boxes...
1223+ ImVec2 current_pos = ImVec2 (bb.Min .x + image_size.x + image_right_padding, bb.Min .y );
11881224
1189- const float midpoint = bb. Min . y + UIStyle. LargeFontSize + spacing;
1190- text = TRANSLATE_PLURAL_SSTR ( " Achievements " , " %n points " , " Achievement points " , cheevo-> points );
1191- const ImVec2 points_size =
1192- UIStyle.Font -> CalcTextSizeA (UIStyle. MediumFontSize , UIStyle. NormalFontWeight , FLT_MAX, 0 . 0f , IMSTR_START_END (text));
1193- const float points_template_start = bb. Max . x - points_template_size. x ;
1194- const float points_start = points_template_start + ((points_template_size. x - points_size. x ) * 0 . 5f ) ;
1225+ // -- Title --
1226+ const ImRect title_bb (current_pos, current_pos + title_size );
1227+ const u32 text_color = ImGui::GetColorU32 (UIStyle. SecondaryTextColor );
1228+ RenderShadowedTextClipped (dl, UIStyle.Font , title_font_size, title_font_weight, title_bb. Min , title_bb. Max ,
1229+ text_color, title, &title_size, ImVec2 ( 0 . 0f , 0 . 0f ), max_title_width, &title_bb) ;
1230+ current_pos. y += title_size. y + spacing ;
11951231
1196- std::string_view right_icon_text;
1197- switch (cheevo-> type )
1232+ // -- Type Badge --
1233+ if (!type_badge_text. empty () )
11981234 {
1199- case RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE:
1200- right_icon_text = ICON_PF_ACHIEVEMENTS_MISSABLE; // Missable
1201- break ;
1202-
1203- case RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION:
1204- right_icon_text = ICON_PF_ACHIEVEMENTS_PROGRESSION; // Progression
1205- break ;
1206-
1207- case RC_CLIENT_ACHIEVEMENT_TYPE_WIN:
1208- right_icon_text = ICON_PF_ACHIEVEMENTS_WIN; // Win Condition
1209- break ;
1210-
1211- // Just use the lock for standard achievements.
1212- case RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD:
1213- default :
1214- right_icon_text = is_unlocked ? ICON_FA_UNLOCK : ICON_FA_LOCK;
1215- break ;
1235+ const ImVec2 type_badge_pos (title_bb.Min .x + title_size.x + type_badge_spacing,
1236+ ImFloor (title_bb.Min .y + (title_font_size - type_badge_size.y ) * 0 .5f ));
1237+ dl->AddRectFilled (type_badge_pos, type_badge_pos + type_badge_size, type_badge_bg_color, type_badge_rounding);
1238+
1239+ const ImVec2 type_badge_text_pos = type_badge_pos + type_badge_padding;
1240+ const ImVec4 type_badge_text_clip = ImVec4 (type_badge_pos.x , type_badge_pos.y , type_badge_pos.x + type_badge_size.x ,
1241+ type_badge_pos.y + type_badge_size.y );
1242+ dl->AddText (UIStyle.Font , type_badge_font_size, type_badge_font_weight, type_badge_text_pos,
1243+ IM_COL32 (255 , 255 , 255 , 255 ), IMSTR_START_END (type_badge_text), 0 .0f , &type_badge_text_clip);
12161244 }
12171245
1218- const ImVec2 right_icon_size = UIStyle.Font ->CalcTextSizeA (UIStyle.LargeFontSize , UIStyle.BoldFontWeight , FLT_MAX,
1219- 0 .0f , IMSTR_START_END (right_icon_text));
1220-
1221- const float text_start_x = bb.Min .x + image_size.x + LayoutScale (15 .0f );
1222- const ImRect title_bb (ImVec2 (text_start_x, bb.Min .y ), ImVec2 (points_start, midpoint));
1223- const ImRect summary_bb (ImVec2 (text_start_x, midpoint), ImVec2 (points_start, midpoint + summary_text_size.y ));
1224- const ImRect unlock_rarity_bb (summary_bb.Min .x , summary_bb.Max .y + spacing, summary_bb.Max .x ,
1225- summary_bb.Max .y + unlock_rarity_height);
1226- const ImRect points_bb (ImVec2 (points_start, midpoint), bb.Max );
1227- const ImRect lock_bb (ImVec2 (points_template_start + ((points_template_size.x - right_icon_size.x ) * 0 .5f ), bb.Min .y ),
1228- ImVec2 (bb.Max .x , midpoint));
1229-
1230- RenderShadowedTextClipped (UIStyle.Font , UIStyle.LargeFontSize , UIStyle.BoldFontWeight , title_bb.Min , title_bb.Max ,
1231- text_color, cheevo->title , nullptr , ImVec2 (0 .0f , 0 .0f ), 0 .0f , &title_bb);
1232- RenderShadowedTextClipped (UIStyle.Font , UIStyle.LargeFontSize , UIStyle.BoldFontWeight , lock_bb.Min , lock_bb.Max ,
1233- text_color, right_icon_text, &right_icon_size, ImVec2 (0 .0f , 0 .0f ), 0 .0f , &lock_bb);
1234- RenderShadowedTextClipped (UIStyle.Font , UIStyle.MediumFontSize , UIStyle.NormalFontWeight , points_bb.Min ,
1235- points_bb.Max , summary_color, text, &points_size, ImVec2 (0 .0f , 0 .0f ), 0 .0f , &points_bb);
1236-
1237- if (cheevo->description && summary_length > 0 )
1246+ // -- Description --
1247+ const u32 description_color = ImGui::GetColorU32 (DarkerColor (UIStyle.SecondaryTextColor ));
1248+ if (!description.empty ())
12381249 {
1239- RenderShadowedTextClipped (UIStyle.Font , UIStyle.MediumFontSize , UIStyle.NormalFontWeight , summary_bb.Min ,
1240- summary_bb.Max , summary_color, std::string_view (cheevo->description , summary_length),
1241- &summary_text_size, ImVec2 (0 .0f , 0 .0f ), summary_wrap_width, &summary_bb);
1250+ const ImRect description_bb (current_pos, current_pos + description_size);
1251+ RenderShadowedTextClipped (dl, UIStyle.Font , subtitle_font_size, subtitle_font_weight, description_bb.Min ,
1252+ description_bb.Max , description_color, description, &description_size, ImVec2 (0 .0f , 0 .0f ),
1253+ max_text_width, &description_bb);
1254+ current_pos.y += description_size.y + spacing;
12421255 }
12431256
1257+ // -- Rarity --
12441258 // display hc if hc is active
12451259 const float rarity_to_display =
12461260 rc_client_get_hardcore_enabled (Achievements::GetClient ()) ? cheevo->rarity_hardcore : cheevo->rarity ;
1247-
1261+ const ImRect rarity_bb (current_pos, ImVec2 (current_pos.x + max_text_width, current_pos.y + UIStyle.MediumFontSize ));
1262+ const u32 rarity_color = ImGui::GetColorU32 (DarkerColor (DarkerColor (UIStyle.SecondaryTextColor )));
12481263 if (is_unlocked)
12491264 {
12501265 const std::string date =
12511266 Host::FormatNumber (Host::NumberFormatType::LongDateTime, static_cast <s64>(cheevo->unlock_time ));
12521267 text.format (TRANSLATE_FS (" Achievements" , " Unlocked: {} | {:.1f}% of players have this achievement" ), date,
12531268 rarity_to_display);
12541269
1255- RenderShadowedTextClipped (UIStyle.Font , UIStyle.MediumFontSize , UIStyle.NormalFontWeight , unlock_rarity_bb.Min ,
1256- unlock_rarity_bb.Max , rarity_color, text, nullptr , ImVec2 (0 .0f , 0 .0f ), 0 .0f ,
1257- &unlock_rarity_bb);
1270+ RenderShadowedTextClipped (dl, UIStyle.Font , subtitle_font_size, subtitle_font_weight, rarity_bb.Min , rarity_bb.Max ,
1271+ rarity_color, text, nullptr , ImVec2 (0 .0f , 0 .0f ), 0 .0f , &rarity_bb);
12581272 }
12591273 else
12601274 {
12611275 text.format (TRANSLATE_FS (" Achievements" , " {:.1f}% of players have this achievement" ), rarity_to_display);
1262- RenderShadowedTextClipped (UIStyle.Font , UIStyle.MediumFontSize , UIStyle.NormalFontWeight , unlock_rarity_bb.Min ,
1263- unlock_rarity_bb.Max , rarity_color, text, nullptr , ImVec2 (0 .0f , 0 .0f ), 0 .0f ,
1264- &unlock_rarity_bb);
1276+ RenderShadowedTextClipped (dl, UIStyle.Font , subtitle_font_size, subtitle_font_weight, rarity_bb.Min , rarity_bb.Max ,
1277+ rarity_color, text, nullptr , ImVec2 (0 .0f , 0 .0f ), 0 .0f , &rarity_bb);
12651278 }
1279+ current_pos.y += UIStyle.MediumFontSize + spacing;
12661280
1267- if (!is_unlocked && is_measured)
1281+ if (is_measured)
12681282 {
1269- ImDrawList* dl = ImGui::GetWindowDrawList ();
1270- const float progress_height = LayoutScale (progress_height_unscaled);
1271- const float progress_spacing = LayoutScale (progress_spacing_unscaled);
12721283 const float progress_rounding = LayoutScale (progress_rounding_unscaled);
1273- const ImRect progress_bb (summary_bb.Min .x , unlock_rarity_bb.Max .y + progress_spacing,
1274- summary_bb.Max .x - progress_spacing,
1275- unlock_rarity_bb.Max .y + progress_spacing + progress_height);
1284+ const ImRect progress_bb (current_pos,
1285+ ImVec2 (max_text_width, current_pos.y + LayoutScale (progress_height_unscaled)));
12761286 const float fraction = cheevo->measured_percent * 0 .01f ;
12771287 dl->AddRectFilled (progress_bb.Min , progress_bb.Max , ImGui::GetColorU32 (UIStyle.PrimaryDarkColor ),
12781288 progress_rounding);
12791289 ImGui::RenderRectFilledRangeH (dl, progress_bb, ImGui::GetColorU32 (UIStyle.SecondaryColor ), 0 .0f , fraction,
12801290 progress_rounding);
12811291
1282- const ImVec2 text_size = UIStyle.Font ->CalcTextSizeA (UIStyle.MediumFontSize , UIStyle.NormalFontWeight , FLT_MAX,
1283- 0 .0f , IMSTR_START_END (measured_progress));
1284- const ImVec2 text_pos (progress_bb.Min .x + ((progress_bb.Max .x - progress_bb.Min .x ) / 2 .0f ) - (text_size.x / 2 .0f ),
1285- progress_bb.Min .y + ((progress_bb.Max .y - progress_bb.Min .y ) / 2 .0f ) - (text_size.y / 2 .0f ));
1286- dl->AddText (UIStyle.Font , UIStyle.MediumFontSize , UIStyle.NormalFontWeight , text_pos,
1292+ const ImVec2 text_size = UIStyle.Font ->CalcTextSizeA (subtitle_font_size, subtitle_font_weight, FLT_MAX, 0 .0f ,
1293+ IMSTR_START_END (measured_progress));
1294+ const ImVec2 text_pos =
1295+ ImFloor (ImVec2 (progress_bb.Min .x + ((progress_bb.Max .x - progress_bb.Min .x ) / 2 .0f ) - (text_size.x / 2 .0f ),
1296+ progress_bb.Min .y + ((progress_bb.Max .y - progress_bb.Min .y ) / 2 .0f ) - (text_size.y / 2 .0f )));
1297+ dl->AddText (UIStyle.Font , subtitle_font_size, subtitle_font_weight, text_pos,
12871298 ImGui::GetColorU32 (UIStyle.PrimaryTextColor ), IMSTR_START_END (measured_progress));
12881299 }
12891300
1301+ // right side items
1302+ current_pos = ImVec2 (bb.Max .x - right_side_size.x , bb.Min .y );
1303+
1304+ // -- Lock Icon and Points --
1305+ const std::string_view lock_text = is_unlocked ? ICON_EMOJI_UNLOCKED : ICON_FA_LOCK;
1306+ const ImVec2 lock_size =
1307+ UIStyle.Font ->CalcTextSizeA (title_font_size, 0 .0f , FLT_MAX, 0 .0f , IMSTR_START_END (lock_text));
1308+ const ImRect lock_bb (current_pos, ImVec2 (bb.Max .x , current_pos.y + lock_size.y ));
1309+ RenderShadowedTextClipped (dl, UIStyle.Font , title_font_size, 0 .0f , lock_bb.Min , lock_bb.Max , text_color, lock_text,
1310+ &lock_size, ImVec2 (0 .5f , 0 .0f ), 0 .0f , &lock_bb);
1311+ current_pos.y += lock_size.y + spacing;
1312+
1313+ text = TRANSLATE_PLURAL_SSTR (" Achievements" , " %n points" , " Achievement points" , cheevo->points );
1314+ const ImVec2 points_size =
1315+ UIStyle.Font ->CalcTextSizeA (subtitle_font_size, subtitle_font_weight, FLT_MAX, 0 .0f , IMSTR_START_END (text));
1316+ const ImRect points_bb (current_pos, ImVec2 (bb.Max .x , current_pos.y + points_size.y ));
1317+ RenderShadowedTextClipped (dl, UIStyle.Font , subtitle_font_size, subtitle_font_weight, points_bb.Min , points_bb.Max ,
1318+ description_color, text, &points_size, ImVec2 (0 .5f , 0 .0f ), 0 .0f , &points_bb);
1319+
12901320 if (clicked)
12911321 {
1292- const SmallString url = SmallString::from_format (fmt::runtime (ACHEIVEMENT_DETAILS_URL_TEMPLATE), cheevo->id );
1322+ const std::string url = fmt::format (fmt::runtime (ACHEIVEMENT_DETAILS_URL_TEMPLATE), cheevo->id );
12931323 INFO_LOG (" Opening achievement details: {}" , url);
12941324 Host::OpenURL (url);
12951325 }
0 commit comments