@@ -696,6 +696,9 @@ namespace FullscreenUI
696696 // For when we have no GameList entry
697697 static void DrawFallbackCover (const ImVec2& size);
698698 static void DrawFallbackCover (ImDrawList* draw_list, const ImVec2& min, const ImVec2& max);
699+ static std::string_view TrimString (const std::pair<ImFont*, float >& font, std::string_view str, float available_space);
700+ static constexpr const char * g_ellipsis = " \xe2\x80\xa6 " ;
701+ static bool s_prefer_english_titles = false ;
699702
700703 // Lazily populated cover images.
701704 static std::unordered_map<std::string, std::string> s_cover_image_map;
@@ -909,6 +912,11 @@ void FullscreenUI::GamepadLayoutChanged()
909912 ApplyLayoutSettings ();
910913}
911914
915+ void FullscreenUI::PreferEnglishGameListChanged ()
916+ {
917+ s_prefer_english_titles = Host::GetBaseBoolSettingValue (" UI" , " PreferEnglishGameList" , false );
918+ }
919+
912920// When drawing an svg to a non-integer size, we get a padded texture.
913921// This function crops off this padding by setting the image UV for the draw.
914922// We currently only use integer sizes for images, but I wrote this before checking that.
@@ -970,6 +978,7 @@ bool FullscreenUI::Initialize()
970978 ImGuiFullscreen::UpdateLayoutScale ();
971979 ImGuiFullscreen::UpdateFontScale ();
972980 ApplyLayoutSettings ();
981+ PreferEnglishGameListChanged ();
973982
974983 if (!ImGuiFullscreen::Initialize (" fullscreenui/placeholder.png" ) || !LoadResources ())
975984 {
@@ -987,7 +996,7 @@ bool FullscreenUI::Initialize()
987996
988997 if (VMManager::HasValidVM ())
989998 {
990- UpdateGameDetails (VMManager::GetDiscPath (), VMManager::GetDiscSerial (), VMManager::GetTitle (true ), VMManager::GetDiscCRC (),
999+ UpdateGameDetails (VMManager::GetDiscPath (), VMManager::GetDiscSerial (), VMManager::GetTitle (s_prefer_english_titles ), VMManager::GetDiscCRC (),
9911000 VMManager::GetCurrentCRC ());
9921001 }
9931002 else
@@ -3710,7 +3719,7 @@ void FullscreenUI::DrawSettingsWindow()
37103719 if (s_game_settings_entry)
37113720 {
37123721 NavTitle (SmallString::from_format (
3713- " {} ({})" , Host::TranslateToCString (TR_CONTEXT, titles[static_cast <u32 >(pages[index])]), s_game_settings_entry->GetTitle (true )));
3722+ " {} ({})" , Host::TranslateToCString (TR_CONTEXT, titles[static_cast <u32 >(pages[index])]), s_game_settings_entry->GetTitle (s_prefer_english_titles )));
37143723 }
37153724 else
37163725 {
@@ -3860,8 +3869,8 @@ void FullscreenUI::DrawSummarySettingsPage()
38603869
38613870 if (s_game_settings_entry)
38623871 {
3863- if (MenuButton (FSUI_ICONSTR (ICON_FA_TAG, " Title" ), s_game_settings_entry->GetTitle (true ).c_str (), true ))
3864- CopyTextToClipboard (FSUI_STR (" Game title copied to clipboard." ), s_game_settings_entry->GetTitle (true ));
3872+ if (MenuButton (FSUI_ICONSTR (ICON_FA_TAG, " Title" ), s_game_settings_entry->GetTitle (s_prefer_english_titles ).c_str (), true ))
3873+ CopyTextToClipboard (FSUI_STR (" Game title copied to clipboard." ), s_game_settings_entry->GetTitle (s_prefer_english_titles ));
38653874 if (MenuButton (FSUI_ICONSTR (ICON_FA_PAGER, " Serial" ), s_game_settings_entry->serial .c_str (), true ))
38663875 CopyTextToClipboard (FSUI_STR (" Game serial copied to clipboard." ), s_game_settings_entry->serial );
38673876 if (MenuButton (FSUI_ICONSTR (ICON_FA_CODE, " CRC" ), fmt::format (" {:08X}" , s_game_settings_entry->crc ).c_str (), true ))
@@ -7749,7 +7758,7 @@ void FullscreenUI::PopulateGameListEntryList()
77497758 }
77507759
77517760 // fallback to title when all else is equal
7752- const int res = StringUtil::Strcasecmp (lhs->GetTitleSort (true ).c_str (), rhs->GetTitleSort (true ).c_str ());
7761+ const int res = StringUtil::Strcasecmp (lhs->GetTitleSort (s_prefer_english_titles ).c_str (), rhs->GetTitleSort (s_prefer_english_titles ).c_str ());
77537762 return reverse ? (res > 0 ) : (res < 0 );
77547763 });
77557764}
@@ -7855,6 +7864,19 @@ void FullscreenUI::DrawGameListWindow()
78557864 }
78567865}
78577866
7867+ std::string_view FullscreenUI::TrimString (const std::pair<ImFont*, float >& font, std::string_view str, float available_space)
7868+ {
7869+ const char * beg = str.data ();
7870+ const char * end = beg + str.size ();
7871+ float full_width = font.first ->CalcTextSizeA (font.second , INFINITY, 0 , beg, end).x ;
7872+ if (full_width <= available_space)
7873+ return str;
7874+ float ellipsis_width = ImGui::CalcTextSize (g_ellipsis).x ;
7875+ const char * trimmed = end;
7876+ font.first ->CalcTextSizeA (font.second , available_space - ellipsis_width, 0 , beg, end, &trimmed);
7877+ return std::string_view (beg, trimmed);
7878+ }
7879+
78587880void FullscreenUI::DrawGameList (const ImVec2& heading_size)
78597881{
78607882 ImGui::PushStyleColor (ImGuiCol_WindowBg, UIBackgroundColor);
@@ -7905,10 +7927,10 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
79057927 const float text_start_x = bb.Min .x + image_size.x + LayoutScale (15 .0f );
79067928 const ImRect title_bb (ImVec2 (text_start_x, bb.Min .y ), ImVec2 (bb.Max .x , midpoint));
79077929 const ImRect summary_bb (ImVec2 (text_start_x, midpoint), bb.Max );
7930+ const std::string& title = entry->GetTitle (s_prefer_english_titles);
79087931
79097932 ImGui::PushFont (g_large_font.first , g_large_font.second );
7910- // TODO: Fix font fallback issues and enable native-language titles
7911- ImGui::RenderTextClipped (title_bb.Min , title_bb.Max , entry->GetTitle (true ).c_str (), entry->GetTitle (true ).c_str () + entry->GetTitle (true ).size (), nullptr ,
7933+ ImGui::RenderTextClipped (title_bb.Min , title_bb.Max , title.c_str (), title.c_str () + title.size (), nullptr ,
79127934 ImVec2 (0 .0f , 0 .0f ), &title_bb);
79137935 ImGui::PopFont ();
79147936
@@ -7986,13 +8008,14 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
79868008 {
79878009 // title
79888010 ImGui::PushFont (g_large_font.first , g_large_font.second );
7989- const std::string_view title (std::string_view (selected_entry->GetTitle (true )).substr (0 , 37 ));
8011+ const std::string_view full_title (selected_entry->GetTitle (s_prefer_english_titles));
8012+ std::string_view title = TrimString (g_large_font, full_title, work_width);
79908013 text_width = ImGui::CalcTextSize (title.data (), title.data () + title.length (), false , work_width).x ;
7991- if (title.length () != selected_entry-> GetTitle ( true ) .length ())
7992- text_width += ImGui::CalcTextSize (" ... " , nullptr , false , - 1 . 0f ).x ;
8014+ if (title.length () != full_title .length ())
8015+ text_width += ImGui::CalcTextSize (g_ellipsis ).x ;
79938016 ImGui::SetCursorPosX ((work_width - text_width) / 2 .0f );
79948017 ImGui::TextWrapped (
7995- " %.*s%s" , static_cast <int >(title.size ()), title.data (), (title.length () == selected_entry-> GetTitle ( true ) .length ()) ? " " : " ... " );
8018+ " %.*s%s" , static_cast <int >(title.size ()), title.data (), (title.length () == full_title .length ()) ? " " : g_ellipsis );
79968019 ImGui::PopFont ();
79978020
79988021 ImGui::PushFont (g_medium_font.first , g_medium_font.second );
@@ -8147,9 +8170,10 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
81478170 if (show_titles)
81488171 {
81498172 const ImRect title_bb (ImVec2 (bb.Min .x , bb.Min .y + image_height + title_spacing), bb.Max );
8150- const std::string_view title (std::string_view (entry->GetTitle (true )).substr (0 , 31 ));
8173+ const std::string_view full_title (entry->GetTitle (s_prefer_english_titles));
8174+ const std::string_view title = TrimString (g_medium_font, full_title, title_bb.GetWidth ());
81518175 draw_title.clear ();
8152- fmt::format_to (std::back_inserter (draw_title), " {}{}" , title, (title.length () == entry-> GetTitle ( true ) .length ()) ? " " : " ... " );
8176+ fmt::format_to (std::back_inserter (draw_title), " {}{}" , title, (title.length () == full_title .length ()) ? " " : g_ellipsis );
81538177 ImGui::PushFont (g_medium_font.first , g_medium_font.second );
81548178 ImGui::RenderTextClipped (title_bb.Min , title_bb.Max , draw_title.c_str (), draw_title.c_str () + draw_title.length (), nullptr ,
81558179 ImVec2 (0 .5f , 0 .0f ), &title_bb);
@@ -8198,7 +8222,7 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry)
81988222 options.emplace_back (FSUI_ICONSTR (ICON_FA_SQUARE_XMARK, " Close Menu" ), false );
81998223
82008224 const bool has_resume_state = VMManager::HasSaveStateInSlot (entry->serial .c_str (), entry->crc , -1 );
8201- OpenChoiceDialog (entry->GetTitle (true ).c_str (), false , std::move (options),
8225+ OpenChoiceDialog (entry->GetTitle (s_prefer_english_titles ).c_str (), false , std::move (options),
82028226 [has_resume_state, entry_path = entry->path , entry_serial = entry->serial , entry_title = entry->title , entry_played_time]
82038227 (s32 index, const std::string& title, bool checked) {
82048228 switch (index)
0 commit comments