GameList: Synchronize settings between FullscreenUI and Qt

Also share translations with other hosts.
This commit is contained in:
Stenzek
2026-10-10 21:47:40 +10:00
parent e02bb9c748
commit 07d3a934a6
16 changed files with 686 additions and 621 deletions
+5 -1
View File
@@ -1080,6 +1080,10 @@ void FullscreenUI::BeginChangeDiscOnCoreThread(bool return_to_game)
if (const GameDatabase::Entry* entry = System::GetGameDatabaseEntry(); entry && entry->disc_set)
{
// Don't hold both settings and game list lock.
const bool localized_titles = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES);
// Another load request cannot start because we have the lock held.
auto lock = GameList::GetLock();
if (!GameList::IsGameListLoaded())
@@ -1108,7 +1112,7 @@ void FullscreenUI::BeginChangeDiscOnCoreThread(bool return_to_game)
// This is still needed because a scan-in-progress will report loaded.
GameList::EnsureLoaded(lock);
auto matches = GameList::GetEntriesInDiscSet(entry->disc_set, GameList::ShouldShowLocalizedTitles());
auto matches = GameList::GetEntriesInDiscSet(entry->disc_set, localized_titles);
if (matches.size() > 1)
{
ChoiceDialogOptions options;
+86 -170
View File
@@ -1,16 +1,18 @@
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <[email protected]>
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <[email protected]>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "achievements.h"
#include "core.h"
#include "fullscreenui_private.h"
#include "game_list.h"
#include "host.h"
#include "system.h"
#include "video_thread.h"
#include "util/gpu_texture.h"
#include "util/imgui_manager.h"
#include "common/bitutils.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/path.h"
@@ -22,13 +24,6 @@
namespace FullscreenUI {
enum class GameListView : u8
{
Grid,
List,
Count
};
static void DrawGameList(const ImVec2& heading_size);
static void DrawGameGrid(const ImVec2& heading_size);
static void HandleGameListActivate(const GameList::Entry* entry);
@@ -53,7 +48,14 @@ struct GameListLocals
std::unordered_map<std::string, std::string> cover_image_map;
std::unordered_map<std::string, std::string> icon_image_map;
std::vector<const GameList::Entry*> game_list_sorted_entries;
GameListView game_list_view = GameListView::Grid;
GameList::Column sort_column = GameList::DEFAULT_SORT_COLUMN;
bool sort_reversed = GameList::DEFAULT_SORT_REVERSED;
bool localized_titles = GameList::DEFAULT_LOCALIZED_TITLES;
bool merge_disc_sets = GameList::DEFAULT_MERGE_DISC_SETS;
bool grid_view = GameList::DEFAULT_FULLSCREENUI_GRID_VIEW;
bool cover_titles = GameList::DEFAULT_COVER_TITLES;
bool compact_mode = true;
bool show_trophy_icons = true;
float game_list_current_selection_timeout = 0.0f;
std::string game_list_current_selection_path;
char game_list_search_string[256];
@@ -148,16 +150,13 @@ void FullscreenUI::DoSetCoverImage(std::string source_path, std::string existing
void FullscreenUI::PopulateGameListEntryList()
{
const s32 sort = Core::GetBaseIntSettingValue("Main", "FullscreenUIGameSort", 0);
const bool reverse = Core::GetBaseBoolSettingValue("Main", "FullscreenUIGameSortReverse", false);
const bool merge_disc_sets = Core::GetBaseBoolSettingValue("Main", "FullscreenUIMergeDiscSets", true);
const std::string_view string_filter = s_game_list_locals.game_list_search_string;
s_game_list_locals.game_list_sorted_entries.clear();
s_game_list_locals.game_list_sorted_entries.reserve(GameList::GetEntryCount());
for (const GameList::Entry& entry : GameList::GetEntries())
{
if (merge_disc_sets)
if (s_game_list_locals.merge_disc_sets)
{
if (entry.disc_set_member)
continue;
@@ -182,110 +181,11 @@ void FullscreenUI::PopulateGameListEntryList()
s_game_list_locals.game_list_sorted_entries.push_back(&entry);
}
std::sort(s_game_list_locals.game_list_sorted_entries.begin(), s_game_list_locals.game_list_sorted_entries.end(),
[sort, reverse](const GameList::Entry* lhs, const GameList::Entry* rhs) {
switch (sort)
{
case 0: // Type
{
const GameList::EntryType lst = lhs->GetSortType();
const GameList::EntryType rst = rhs->GetSortType();
if (lst != rst)
return reverse ? (lst > rst) : (lst < rst);
}
break;
case 1: // Serial
{
if (lhs->serial != rhs->serial)
return reverse ? (lhs->serial > rhs->serial) : (lhs->serial < rhs->serial);
}
break;
case 2: // Title
break;
case 3: // File Title
{
const std::string_view lhs_title(Path::GetFileTitle(lhs->path));
const std::string_view rhs_title(Path::GetFileTitle(rhs->path));
const int res = StringUtil::Strncasecmp(lhs_title.data(), rhs_title.data(),
std::min(lhs_title.size(), rhs_title.size()));
if (res != 0)
return reverse ? (res > 0) : (res < 0);
}
break;
case 4: // Time Played
{
if (lhs->total_played_time != rhs->total_played_time)
{
return reverse ? (lhs->total_played_time > rhs->total_played_time) :
(lhs->total_played_time < rhs->total_played_time);
}
}
break;
case 5: // Last Played (reversed by default)
{
if (lhs->last_played_time != rhs->last_played_time)
{
return reverse ? (lhs->last_played_time < rhs->last_played_time) :
(lhs->last_played_time > rhs->last_played_time);
}
}
break;
case 6: // File Size
{
if (lhs->file_size != rhs->file_size)
{
return reverse ? (lhs->file_size > rhs->file_size) : (lhs->file_size < rhs->file_size);
}
}
break;
case 7: // Uncompressed Size
{
if (lhs->uncompressed_size != rhs->uncompressed_size)
{
return reverse ? (lhs->uncompressed_size > rhs->uncompressed_size) :
(lhs->uncompressed_size < rhs->uncompressed_size);
}
}
break;
case 8: // Achievements
{
// sort by unlock percentage
const float unlock_lhs =
(lhs->num_achievements > 0) ?
(static_cast<float>(std::max(lhs->unlocked_achievements, lhs->unlocked_achievements_hc)) /
static_cast<float>(lhs->num_achievements)) :
0;
const float unlock_rhs =
(rhs->num_achievements > 0) ?
(static_cast<float>(std::max(rhs->unlocked_achievements, rhs->unlocked_achievements_hc)) /
static_cast<float>(rhs->num_achievements)) :
0;
if (std::abs(unlock_lhs - unlock_rhs) >= 0.0001f)
return reverse ? (unlock_lhs > unlock_rhs) : (unlock_lhs < unlock_rhs);
// order by achievement count
if (lhs->num_achievements != rhs->num_achievements)
return reverse ? (rhs->num_achievements < lhs->num_achievements) :
(lhs->num_achievements < rhs->num_achievements);
}
}
// fallback to title when all else is equal
const int res = StringUtil::CompareNoCase(lhs->GetSortTitle(), rhs->GetSortTitle());
if (res != 0)
return reverse ? (res > 0) : (res < 0);
// fallback to path when all else is equal
return reverse ? (lhs->path > rhs->path) : (lhs->path < rhs->path);
});
std::ranges::sort(s_game_list_locals.game_list_sorted_entries, [](const GameList::Entry* lhs,
const GameList::Entry* rhs) {
return GameList::CompareEntryLessThan(s_game_list_locals.sort_reversed ? rhs : lhs,
s_game_list_locals.sort_reversed ? lhs : rhs, s_game_list_locals.sort_column);
});
}
void FullscreenUI::DrawGameListWindow()
@@ -300,10 +200,6 @@ void FullscreenUI::DrawGameListWindow()
if (BeginFullscreenWindow(ImVec2(0.0f, 0.0f), heading_size, "gamelist_view",
MulAlpha(UIStyle.PrimaryColor, GetBackgroundAlpha())))
{
static constexpr const char* icons[] = {ICON_FA_TABLE_CELLS_LARGE, ICON_FA_LIST};
static constexpr const char* titles[] = {FSUI_NSTR("Game Grid"), FSUI_NSTR("Game List")};
static constexpr u32 count = static_cast<u32>(std::size(titles));
BeginNavBar();
if (NavButton(ICON_PF_NAVIGATION_BACK, true, true))
@@ -312,7 +208,7 @@ void FullscreenUI::DrawGameListWindow()
[]() { SwitchToMainWindow(MainWindowType::Landing); });
}
NavTitle(Host::TranslateToStringView(FSUI_TR_CONTEXT, titles[static_cast<u32>(s_game_list_locals.game_list_view)]));
NavTitle(s_game_list_locals.grid_view ? FSUI_VSTR("Game Grid") : FSUI_VSTR("Game List"));
static constexpr const float& search_font_size = UIStyle.MediumFontSize;
static constexpr const float& search_font_weight = UIStyle.NormalFontWeight;
@@ -348,14 +244,18 @@ void FullscreenUI::DrawGameListWindow()
ImGui::PopStyleColor(2);
ImGui::SetCursorPos(prev_cursor_pos);
RightAlignNavButtons(count);
RightAlignNavButtons(2u);
for (u32 i = 0; i < count; i++)
for (u32 grid = 0; grid < 2; grid++)
{
if (NavButton(icons[i], static_cast<GameListView>(i) == s_game_list_locals.game_list_view, true))
if (NavButton(grid ? ICON_FA_TABLE_CELLS_LARGE : ICON_FA_LIST, grid == BoolToUInt32(s_game_list_locals.grid_view),
true))
{
BeginTransition([i]() {
s_game_list_locals.game_list_view = static_cast<GameListView>(i);
BeginTransition([grid]() {
s_game_list_locals.grid_view = ConvertToBoolUnchecked(grid);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_FULLSCREENUI_GRID_VIEW,
s_game_list_locals.grid_view);
Host::CommitBaseSettingChanges();
QueueResetFocus(FocusResetType::ViewChanged);
});
}
@@ -366,17 +266,10 @@ void FullscreenUI::DrawGameListWindow()
EndFullscreenWindow();
switch (s_game_list_locals.game_list_view)
{
case GameListView::Grid:
DrawGameGrid(heading_size);
break;
case GameListView::List:
DrawGameList(heading_size);
break;
default:
break;
}
if (s_game_list_locals.grid_view)
DrawGameGrid(heading_size);
else
DrawGameList(heading_size);
// note: has to come afterwards
if (!AreAnyDialogsOpen())
@@ -386,8 +279,10 @@ void FullscreenUI::DrawGameListWindow()
{
EnqueueSoundEffect(SFX_NAV_MOVE);
BeginTransition([]() {
s_game_list_locals.game_list_view =
(s_game_list_locals.game_list_view == GameListView::Grid) ? GameListView::List : GameListView::Grid;
s_game_list_locals.grid_view = !s_game_list_locals.grid_view;
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_FULLSCREENUI_GRID_VIEW,
s_game_list_locals.grid_view);
Host::CommitBaseSettingChanges();
QueueResetFocus(FocusResetType::ViewChanged);
});
}
@@ -450,8 +345,6 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
[]() { SwitchToMainWindow(MainWindowType::Landing); });
}
const bool compact_mode = Core::GetBaseBoolSettingValue("Main", "FullscreenUIGameListCompactMode", true);
const bool show_localized_titles = GameList::ShouldShowLocalizedTitles();
auto game_list_lock = GameList::GetLock();
const GameList::Entry* selected_entry = nullptr;
PopulateGameListEntryList();
@@ -462,8 +355,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
if (BeginFullscreenColumnWindow(0.0f, -530.0f, "game_list_entries", GetTransparentBackgroundColor(),
ImVec2(LAYOUT_MENU_WINDOW_X_PADDING, LAYOUT_MENU_WINDOW_Y_PADDING)))
{
const float image_size = compact_mode ? UIStyle.LargeFontSize : LayoutScale(50.0f);
const float row_image_padding = LayoutScale(compact_mode ? 15.0f : 15.0f);
const float image_size = s_game_list_locals.compact_mode ? UIStyle.LargeFontSize : LayoutScale(50.0f);
const float row_image_padding = LayoutScale(s_game_list_locals.compact_mode ? 15.0f : 15.0f);
const float row_left_margin = image_size + row_image_padding;
ResetFocusHere();
@@ -476,7 +369,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
for (const GameList::Entry* entry : s_game_list_locals.game_list_sorted_entries)
{
if (!compact_mode)
if (!s_game_list_locals.compact_mode)
{
if (entry->serial.empty())
{
@@ -489,20 +382,22 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
}
}
const MenuButtonBounds mbb(entry->GetDisplayTitle(show_localized_titles), {}, summary, row_left_margin);
const MenuButtonBounds mbb(entry->GetDisplayTitle(s_game_list_locals.localized_titles), {}, summary,
row_left_margin);
bool visible, hovered;
bool pressed = MenuButtonFrame(GetKeyForGameListEntry(entry), true, mbb.frame_bb, &visible, &hovered);
if (!visible)
continue;
DrawGameListCover(entry, false, true, false, show_localized_titles, ImGui::GetWindowDrawList(),
DrawGameListCover(entry, false, true, false, s_game_list_locals.localized_titles, ImGui::GetWindowDrawList(),
ImRect(ImVec2(mbb.title_bb.Min.x - row_left_margin, mbb.title_bb.Min.y),
ImVec2(mbb.title_bb.Min.x - row_image_padding, mbb.title_bb.Min.y + image_size)));
RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, mbb.title_bb.Min,
mbb.title_bb.Max, text_color, entry->GetDisplayTitle(show_localized_titles),
&mbb.title_size, ImVec2(0.0f, 0.0f), mbb.title_size.x, &mbb.title_bb);
mbb.title_bb.Max, text_color,
entry->GetDisplayTitle(s_game_list_locals.localized_titles), &mbb.title_size,
ImVec2(0.0f, 0.0f), mbb.title_size.x, &mbb.title_bb);
if (!summary.empty())
{
@@ -605,7 +500,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
if (selected_entry)
{
const ImVec4 subtitle_text_color = DarkerColor(ImGui::GetStyle().Colors[ImGuiCol_Text]);
const std::string_view title = selected_entry->GetDisplayTitle(show_localized_titles);
const std::string_view title = selected_entry->GetDisplayTitle(s_game_list_locals.localized_titles);
// title
ImGui::PushFont(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight);
@@ -813,9 +708,6 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
BeginMenuButtons(0, 0.0f, 15.0f, 15.0f, 20.0f, 20.0f);
const ImGuiStyle& style = ImGui::GetStyle();
const bool show_trophy_icons = Core::GetBaseBoolSettingValue("Main", "FullscreenUIShowTrophyIcons", true);
const bool show_titles = Core::GetBaseBoolSettingValue("Main", "FullscreenUIShowGridTitles", true);
const bool show_localized_titles = GameList::ShouldShowLocalizedTitles();
const float title_font_size = UIStyle.MediumLargeFontSize;
const float title_font_weight = UIStyle.NormalFontWeight;
@@ -856,7 +748,7 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
// tends to break when scrolling vertically - it goes left/right. Precompute the maximum item height for the row
// first, and make all items the same size to work around this.
const GameList::Entry* entry = s_game_list_locals.game_list_sorted_entries[entry_index];
if (grid_x == 0 && show_titles)
if (grid_x == 0 && s_game_list_locals.cover_titles)
{
row_item_height = 0.0f;
@@ -865,7 +757,7 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
for (size_t row_entry_index = entry_index; row_entry_index < row_entry_index_end; row_entry_index++)
{
const GameList::Entry* row_entry = s_game_list_locals.game_list_sorted_entries[row_entry_index];
const std::string_view row_title = row_entry->GetDisplayTitle(show_localized_titles);
const std::string_view row_title = row_entry->GetDisplayTitle(s_game_list_locals.localized_titles);
const ImVec2 this_title_size = UIStyle.Font->CalcTextSizeA(title_font_size, title_font_weight, image_width,
image_width, IMSTR_START_END(row_title));
row_item_height = std::max(row_item_height, this_title_size.y);
@@ -875,9 +767,9 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
}
ImVec2 title_size;
if (show_titles)
if (s_game_list_locals.cover_titles)
{
const std::string_view title = entry->GetDisplayTitle(show_localized_titles);
const std::string_view title = entry->GetDisplayTitle(s_game_list_locals.localized_titles);
title_size = UIStyle.Font->CalcTextSizeA(title_font_size, title_font_weight, image_width, image_width,
IMSTR_START_END(title));
}
@@ -899,9 +791,10 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
bb.Min += style.FramePadding;
bb.Max -= style.FramePadding;
DrawGameListCover(entry, false, false, true, show_localized_titles, dl, ImRect(bb.Min, bb.Min + image_size));
DrawGameListCover(entry, false, false, true, s_game_list_locals.localized_titles, dl,
ImRect(bb.Min, bb.Min + image_size));
if (show_trophy_icons)
if (s_game_list_locals.show_trophy_icons)
{
GPUTexture* const cover_trophy = GetGameListCoverTrophy(entry, image_size);
if (cover_trophy)
@@ -913,11 +806,12 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
}
}
if (show_titles)
if (s_game_list_locals.cover_titles)
{
const ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max);
RenderMultiLineShadowedTextClipped(dl, UIStyle.Font, title_font_size, title_font_weight, title_bb.Min,
title_bb.Max, text_color, entry->GetDisplayTitle(show_localized_titles),
title_bb.Max, text_color,
entry->GetDisplayTitle(s_game_list_locals.localized_titles),
LAYOUT_CENTER_ALIGN_TEXT, image_width, &title_bb);
}
@@ -984,7 +878,7 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry)
};
const GameDatabase::DiscSetEntry* dsentry = entry->dbentry->disc_set;
OpenChoiceDialog(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles()), false, std::move(options),
OpenChoiceDialog(entry->GetDisplayTitle(s_game_list_locals.localized_titles), false, std::move(options),
[dsentry](s32 index, const std::string& title, bool checked) mutable {
switch (index)
{
@@ -1023,7 +917,7 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry)
{FSUI_ICONSTR(ICON_FA_DELETE_LEFT, "Reset Play Time"), false},
};
OpenChoiceDialog(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles()), false, std::move(options),
OpenChoiceDialog(entry->GetDisplayTitle(s_game_list_locals.localized_titles), false, std::move(options),
[entry_path = entry->path, entry_serial = entry->serial](s32 index, const std::string& title,
bool checked) mutable {
switch (index)
@@ -1072,7 +966,7 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry)
{FSUI_ICONSTR(ICON_FA_HOURGLASS, "Slow Boot"), false},
};
OpenChoiceDialog(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles()), false, std::move(options),
OpenChoiceDialog(entry->GetDisplayTitle(s_game_list_locals.localized_titles), false, std::move(options),
[entry_path = entry->path](s32 index, const std::string& title, bool checked) mutable {
switch (index)
{
@@ -1120,9 +1014,9 @@ void FullscreenUI::HandleSelectDiscForDiscSet(const GameDatabase::DiscSetEntry*
options.emplace_back(FSUI_ICONVSTR(ICON_FA_SQUARE_XMARK, "Close Menu"), false);
const GameList::Entry* dsgentry = GameList::GetEntryForPath(dsentry->GetSaveTitle());
const bool localized_titles = GameList::ShouldShowLocalizedTitles();
OpenChoiceDialog(fmt::format(FSUI_FSTR("Select Disc for {}"), dsgentry ? dsgentry->GetDisplayTitle(localized_titles) :
dsentry->GetDisplayTitle(localized_titles)),
OpenChoiceDialog(fmt::format(FSUI_FSTR("Select Disc for {}"),
dsgentry ? dsgentry->GetDisplayTitle(s_game_list_locals.localized_titles) :
dsentry->GetDisplayTitle(s_game_list_locals.localized_titles)),
false, std::move(options),
[paths = std::move(paths)](s32 index, const std::string& title, bool checked) {
if (static_cast<u32>(index) >= paths.size())
@@ -1137,9 +1031,8 @@ void FullscreenUI::HandleSelectDiscForDiscSet(const GameDatabase::DiscSetEntry*
void FullscreenUI::SwitchToGameList()
{
s_game_list_locals.game_list_view =
static_cast<GameListView>(std::min(Core::GetBaseUIntSettingValue("Main", "DefaultFullscreenUIGameView", 0),
static_cast<u32>(GameListView::Count) - 1));
ReloadGameListSettings();
s_game_list_locals.game_list_current_selection_path = {};
s_game_list_locals.game_list_current_selection_timeout = 0.0f;
s_game_list_locals.game_list_search_string[0] = '\0';
@@ -1155,6 +1048,29 @@ void FullscreenUI::SwitchToGameList()
SwitchToMainWindow(MainWindowType::GameList);
}
void FullscreenUI::ReloadGameListSettings()
{
s_game_list_locals.sort_column =
GameList::ParseColumnName(
Core::GetBaseStringSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_SORT_COLUMN))
.value_or(GameList::DEFAULT_SORT_COLUMN);
s_game_list_locals.sort_reversed =
Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_SORT_REVERSED, false);
s_game_list_locals.localized_titles = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES);
s_game_list_locals.merge_disc_sets = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_MERGE_DISC_SETS, GameList::DEFAULT_MERGE_DISC_SETS);
s_game_list_locals.grid_view =
Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_FULLSCREENUI_GRID_VIEW,
GameList::DEFAULT_FULLSCREENUI_GRID_VIEW);
s_game_list_locals.cover_titles = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_COVER_TITLES, GameList::DEFAULT_COVER_TITLES);
s_game_list_locals.compact_mode =
Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "GameListCompactMode", true);
s_game_list_locals.show_trophy_icons =
Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "GameListGridTrophyIcons", true);
}
GPUTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry, bool fallback_to_achievements_icon,
bool fallback_to_icon, bool return_default_image)
{
+1
View File
@@ -99,6 +99,7 @@ FileSelectorFilters GetImageFilters();
void ClearGameListState();
void SwitchToGameList();
void ReloadGameListSettings();
void DrawGameListWindow();
void DoStartPath(std::string path, std::string state = std::string(), std::optional<bool> fast_boot = std::nullopt);
+56 -48
View File
@@ -99,7 +99,7 @@ static void StartImageVerification();
static void ProcessImageVerificationResults(std::string path, GameDatabase::TrackVerificationResult verification,
bool result, bool cancelled, Error error);
static void DrawSummarySettingsPage(bool show_localized_titles);
static void DrawSummarySettingsPage();
static void DrawSummarySettingsTrackList();
static void OpenGameTitleActions(const std::string_view& path, const std::string_view& title, bool has_custom_title,
bool is_disc_set_title);
@@ -196,7 +196,7 @@ static void DrawEnumSetting(SettingsInterface* bsi, std::string_view title, std:
std::optional<DataType> (*from_string_function)(std::string_view str),
const char* (*to_string_function)(DataType value),
const char* (*to_display_string_function)(DataType value), SizeType option_count,
bool enabled = true, bool use_dropdown = true);
bool enabled = true, bool use_dropdown = true, void (*changed_callback)() = nullptr);
static void DrawSpeedSelectorSetting(SettingsInterface* bsi, std::string_view title, std::string_view summary,
const char* section, const char* key, float default_value, bool enabled = true);
static void DrawFolderSetting(SettingsInterface* bsi, std::string_view title, const char* section, const char* key,
@@ -1528,7 +1528,8 @@ void FullscreenUI::DrawEnumSetting(SettingsInterface* bsi, std::string_view titl
std::optional<DataType> (*from_string_function)(std::string_view str),
const char* (*to_string_function)(DataType value),
const char* (*to_display_string_function)(DataType value), SizeType option_count,
bool enabled /* = true */, bool use_dropdown /* = true */)
bool enabled /* = true */, bool use_dropdown /* = true */,
void (*changed_callback)() /* = nullptr*/)
{
const bool game_settings = IsEditingGameSettings(bsi);
@@ -1577,17 +1578,21 @@ void FullscreenUI::DrawEnumSetting(SettingsInterface* bsi, std::string_view titl
if (use_dropdown)
{
OpenDropdownDialog(title, std::move(cd_options),
[section = TinyString(section), key = TinyString(key), to_string_function,
[section = TinyString(section), key = TinyString(key), to_string_function, changed_callback,
game_settings](s32 index, const std::string& title) {
apply_option(section, key, to_string_function, game_settings, index);
if (changed_callback)
changed_callback();
});
}
else
{
OpenChoiceDialog(title, false, std::move(cd_options),
[section = TinyString(section), key = TinyString(key), to_string_function,
[section = TinyString(section), key = TinyString(key), to_string_function, changed_callback,
game_settings](s32 index, const std::string& title, bool checked) {
apply_option(section, key, to_string_function, game_settings, index);
if (changed_callback)
changed_callback();
});
}
}
@@ -1918,7 +1923,6 @@ void FullscreenUI::DrawSettingsWindow()
const float bg_alpha = GetBackgroundAlpha();
const bool blur_background = CanBlurBackground() && s_settings_locals.settings_page != SettingsPage::PostProcessing;
const bool show_localized_titles = GameList::ShouldShowLocalizedTitles();
static constexpr const SettingsPage global_pages[] = {
SettingsPage::Interface, SettingsPage::GameList, SettingsPage::BIOS, SettingsPage::Console,
@@ -1968,9 +1972,11 @@ void FullscreenUI::DrawSettingsWindow()
if (NavButton(ICON_PF_NAVIGATION_BACK, true, true))
ReturnToPreviousWindow(TransitionEffect::ZoomOut);
NavTitle(s_settings_locals.game_settings_entry ?
s_settings_locals.game_settings_entry->GetDisplayTitle(show_localized_titles) :
Host::TranslateToStringView(FSUI_TR_CONTEXT, titles[static_cast<u32>(pages[index])].first));
NavTitle(
s_settings_locals.game_settings_entry ?
s_settings_locals.game_settings_entry->GetDisplayTitle(Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES)) :
Host::TranslateToStringView(FSUI_TR_CONTEXT, titles[static_cast<u32>(pages[index])].first));
RightAlignNavButtons(count);
@@ -2029,7 +2035,7 @@ void FullscreenUI::DrawSettingsWindow()
switch (s_settings_locals.settings_page)
{
case SettingsPage::Summary:
DrawSummarySettingsPage(show_localized_titles);
DrawSummarySettingsPage();
break;
case SettingsPage::Interface:
@@ -2188,7 +2194,7 @@ void FullscreenUI::DrawSettingsWindow()
}
}
void FullscreenUI::DrawSummarySettingsPage(bool show_localized_titles)
void FullscreenUI::DrawSummarySettingsPage()
{
BeginMenuButtons();
ResetFocusHere();
@@ -2206,6 +2212,8 @@ void FullscreenUI::DrawSummarySettingsPage(bool show_localized_titles)
{
const float title_width = LayoutScale(200.0f);
const bool allow_customization = !s_settings_locals.game_settings_entry->is_runtime_populated;
const bool show_localized_titles = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES);
const std::string_view title = s_settings_locals.game_settings_entry->GetDisplayTitle(show_localized_titles);
if (MenuButtonWithInlineValue(s_settings_locals.game_settings_entry->has_custom_title ?
FSUI_ICONVSTR(ICON_FA_WINDOW_MAXIMIZE, "Title (*)") :
@@ -2891,48 +2899,48 @@ void FullscreenUI::DrawGameListSettingsPage()
SettingsInterface* bsi = GetEditingSettingsInterface(false);
BeginMenuButtons();
ResetFocusHere();
MenuHeading(FSUI_VSTR("List Settings"));
{
static constexpr const char* view_types[] = {FSUI_NSTR("Game Grid"), FSUI_NSTR("Game List")};
static constexpr const char* sort_types[] = {
FSUI_NSTR("Type"),
FSUI_NSTR("Serial"),
FSUI_NSTR("Title"),
FSUI_NSTR("File Title"),
FSUI_NSTR("Time Played"),
FSUI_NSTR("Last Played"),
FSUI_NSTR("File Size"),
FSUI_NSTR("Uncompressed Size"),
FSUI_NSTR("Achievement Unlock/Count"),
};
ResetFocusHere();
DrawIntListSetting(bsi, FSUI_ICONVSTR(ICON_FA_TABLE_CELLS_LARGE, "Default View"),
FSUI_VSTR("Selects the view that the game list will open to."), "Main",
"DefaultFullscreenUIGameView", 0, view_types);
DrawIntListSetting(bsi, FSUI_ICONVSTR(ICON_FA_SORT, "Sort By"),
FSUI_VSTR("Determines that field that the game list will be sorted by."), "Main",
"FullscreenUIGameSort", 0, sort_types);
DrawToggleSetting(
bool settings_changed = DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_FA_TABLE_CELLS_LARGE, "Grid View"),
FSUI_VSTR("Shows the game list as a grid instead of a vertical list."), GameList::UI_SETTING_SECTION,
GameList::SETTING_KEY_FULLSCREENUI_GRID_VIEW, GameList::DEFAULT_FULLSCREENUI_GRID_VIEW);
DrawEnumSetting(bsi, FSUI_ICONVSTR(ICON_FA_SORT, "Sort By"),
FSUI_VSTR("Determines that field that the game list will be sorted by."),
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_SORT_COLUMN, GameList::DEFAULT_SORT_COLUMN,
&GameList::ParseColumnName, &GameList::GetColumnName, &GameList::GetColumnDisplayName,
GameList::Column::MaxCount, false, true, &FullscreenUI::ReloadGameListSettings);
settings_changed |= DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_FA_ARROW_DOWN_Z_A, "Sort Reversed"),
FSUI_VSTR("Reverses the game list sort order from the default (usually ascending to descending)."), "Main",
"FullscreenUIGameSortReverse", false);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_RECTANGLE_LIST, "Merge Multi-Disc Games"),
FSUI_VSTR("Merges multi-disc games into one item in the game list."), "Main",
"FullscreenUIMergeDiscSets", true);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_LANGUAGE, "Show Localized Titles"),
FSUI_VSTR("Uses localized (native language) titles in the game list."), "UI",
"GameListShowLocalizedTitles", true);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_TROPHY, "Show Achievement Trophy Icons"),
FSUI_VSTR("Shows trophy icons in game grid when games have achievements or have been mastered."),
"Main", "FullscreenUIShowTrophyIcons", true);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_TAGS, "Show Grid View Titles"),
FSUI_VSTR("Shows titles underneath the images in the game grid view."), "Main",
"FullscreenUIShowGridTitles", true);
DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_TEXT_SLASH, "List Compact Mode"),
FSUI_VSTR("Displays only the game title in the list, instead of the title and serial/file name."),
"Main", "FullscreenUIGameListCompactMode", true);
FSUI_VSTR("Reverses the game list sort order from the default (usually ascending to descending)."),
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_SORT_REVERSED, GameList::DEFAULT_SORT_REVERSED);
settings_changed |= DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_RECTANGLE_LIST, "Merge Multi-Disc Games"),
FSUI_VSTR("Merges multi-disc games into one item in the game list."),
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_MERGE_DISC_SETS,
GameList::DEFAULT_MERGE_DISC_SETS);
settings_changed |= DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_LANGUAGE, "Show Localized Titles"),
FSUI_VSTR("Uses localized (native language) titles in the game list."),
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES,
GameList::DEFAULT_LOCALIZED_TITLES);
settings_changed |= DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_FA_TROPHY, "Show Achievement Trophy Icons"),
FSUI_VSTR("Shows trophy icons in game grid when games have achievements or have been mastered."),
GameList::UI_SETTING_SECTION, "GameListGridTrophyIcons", true);
settings_changed |= DrawToggleSetting(bsi, FSUI_ICONVSTR(ICON_FA_TAGS, "Show Grid View Titles"),
FSUI_VSTR("Shows titles underneath the images in the game grid view."),
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_COVER_TITLES,
GameList::DEFAULT_COVER_TITLES);
settings_changed |= DrawToggleSetting(
bsi, FSUI_ICONVSTR(ICON_FA_TEXT_SLASH, "List Compact Mode"),
FSUI_VSTR("Displays only the game title in the list, instead of the title and serial/file name."),
GameList::UI_SETTING_SECTION, "GameListCompactMode", true);
// Need to queue because we have the settings lock...
if (settings_changed)
Host::RunOnCoreThread([]() { VideoThread::RunOnThread(&FullscreenUI::ReloadGameListSettings); });
}
MenuHeading(FSUI_VSTR("Search Directories"));
+2 -8
View File
@@ -71,7 +71,6 @@ TRANSLATE_NOOP("FullscreenUI", "A resume save state was found for this game, but
TRANSLATE_NOOP("FullscreenUI", "AMOLED");
TRANSLATE_NOOP("FullscreenUI", "About");
TRANSLATE_NOOP("FullscreenUI", "Achievement Notifications");
TRANSLATE_NOOP("FullscreenUI", "Achievement Unlock/Count");
TRANSLATE_NOOP("FullscreenUI", "Achievement Unlocks Unconfirmed");
TRANSLATE_NOOP("FullscreenUI", "Achievements");
TRANSLATE_NOOP("FullscreenUI", "Achievements Settings");
@@ -228,7 +227,6 @@ TRANSLATE_NOOP("FullscreenUI", "Debugging Settings");
TRANSLATE_NOOP("FullscreenUI", "Default");
TRANSLATE_NOOP("FullscreenUI", "Default Boot");
TRANSLATE_NOOP("FullscreenUI", "Default Value");
TRANSLATE_NOOP("FullscreenUI", "Default View");
TRANSLATE_NOOP("FullscreenUI", "Default: Disabled");
TRANSLATE_NOOP("FullscreenUI", "Default: Enabled");
TRANSLATE_NOOP("FullscreenUI", "Default: {}");
@@ -387,8 +385,6 @@ TRANSLATE_NOOP("FullscreenUI", "Fast Forward Speed");
TRANSLATE_NOOP("FullscreenUI", "Fast Forward Volume");
TRANSLATE_NOOP("FullscreenUI", "Fast forwards through memory card access, both loading and saving. Can reduce waiting times in games that frequently access memory cards.");
TRANSLATE_NOOP("FullscreenUI", "Fast forwards through the early loading process when fast booting, saving time. Results may vary between games.");
TRANSLATE_NOOP("FullscreenUI", "File Size");
TRANSLATE_NOOP("FullscreenUI", "File Title");
TRANSLATE_NOOP("FullscreenUI", "Filter Framebuffer Uploads");
TRANSLATE_NOOP("FullscreenUI", "Fine Crop Amount");
TRANSLATE_NOOP("FullscreenUI", "Fine Crop Mode");
@@ -436,6 +432,7 @@ TRANSLATE_NOOP("FullscreenUI", "Global Slot {0}##global_slot_{0}");
TRANSLATE_NOOP("FullscreenUI", "Graphics Settings");
TRANSLATE_NOOP("FullscreenUI", "Green Giant");
TRANSLATE_NOOP("FullscreenUI", "Grey Matter");
TRANSLATE_NOOP("FullscreenUI", "Grid View");
TRANSLATE_NOOP("FullscreenUI", "Hardcore Mode");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will not be enabled until the game is restarted. Do you want to restart the game now?");
TRANSLATE_NOOP("FullscreenUI", "Hash Calculation Failed");
@@ -467,7 +464,6 @@ TRANSLATE_NOOP("FullscreenUI", "Interface Settings");
TRANSLATE_NOOP("FullscreenUI", "Internal Resolution");
TRANSLATE_NOOP("FullscreenUI", "Language");
TRANSLATE_NOOP("FullscreenUI", "Language: ");
TRANSLATE_NOOP("FullscreenUI", "Last Played");
TRANSLATE_NOOP("FullscreenUI", "Last Played: ");
TRANSLATE_NOOP("FullscreenUI", "Latency Control");
TRANSLATE_NOOP("FullscreenUI", "Launch Options");
@@ -750,7 +746,6 @@ TRANSLATE_NOOP("FullscreenUI", "Selects the resolution to use in fullscreen mode
TRANSLATE_NOOP("FullscreenUI", "Selects the screen location for achievement and leaderboard notifications.");
TRANSLATE_NOOP("FullscreenUI", "Selects the screen location for challenge/progress indicators, and leaderboard trackers.");
TRANSLATE_NOOP("FullscreenUI", "Selects the type of emulated controller for this port.");
TRANSLATE_NOOP("FullscreenUI", "Selects the view that the game list will open to.");
TRANSLATE_NOOP("FullscreenUI", "Selects which location on the screen messages are displayed.");
TRANSLATE_NOOP("FullscreenUI", "Serial");
TRANSLATE_NOOP("FullscreenUI", "Serial (*)");
@@ -804,6 +799,7 @@ TRANSLATE_NOOP("FullscreenUI", "Shows persistent icons when turbo is active or w
TRANSLATE_NOOP("FullscreenUI", "Shows the current controller state of the system in the bottom-left corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current emulation speed of the system in the top-right corner of the display as a percentage.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current rendering resolution of the system in the top-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the game list as a grid instead of a vertical list.");
TRANSLATE_NOOP("FullscreenUI", "Shows the game you are currently playing as part of your profile in Discord.");
TRANSLATE_NOOP("FullscreenUI", "Shows the host's CPU usage of each system thread in the top-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the host's GPU usage in the top-right corner of the display.");
@@ -867,7 +863,6 @@ TRANSLATE_NOOP("FullscreenUI", "The unlock state for '{}' will be removed. This
TRANSLATE_NOOP("FullscreenUI", "Theme");
TRANSLATE_NOOP("FullscreenUI", "This game was not scanned by DuckStation. Some functionality is not available.");
TRANSLATE_NOOP("FullscreenUI", "Threaded Rendering");
TRANSLATE_NOOP("FullscreenUI", "Time Played");
TRANSLATE_NOOP("FullscreenUI", "Time Played: ");
TRANSLATE_NOOP("FullscreenUI", "Timing out in {:.0f} seconds...");
TRANSLATE_NOOP("FullscreenUI", "Title");
@@ -888,7 +883,6 @@ TRANSLATE_NOOP("FullscreenUI", "Tries to detect FMVs and disable read speedup du
TRANSLATE_NOOP("FullscreenUI", "Trigger");
TRANSLATE_NOOP("FullscreenUI", "Turbo Speed");
TRANSLATE_NOOP("FullscreenUI", "Type");
TRANSLATE_NOOP("FullscreenUI", "Uncompressed Size");
TRANSLATE_NOOP("FullscreenUI", "Undo Load State");
TRANSLATE_NOOP("FullscreenUI", "Ungrouped");
TRANSLATE_NOOP("FullscreenUI", "Unknown");
+297 -77
View File
@@ -165,6 +165,87 @@ ALIGN_TO_CACHE_LINE static State s_state;
} // namespace GameList
const char* const GameList::UI_SETTING_SECTION = "UI";
constexpr const char* const GameList::SETTING_KEY_LOCALIZED_TITLES = "GameListShowLocalizedTitles";
constexpr const char* const GameList::SETTING_KEY_SORT_COLUMN = "GameListSortColumn";
constexpr const char* const GameList::SETTING_KEY_SORT_REVERSED = "GameListSortReversed";
constexpr const char* const GameList::SETTING_KEY_PREFER_ACHIEVEMENT_CONTENT_ICONS =
"GameListPreferAchievementContentIcons";
constexpr const char* const GameList::SETTING_KEY_MERGE_DISC_SETS = "GameListMergeDiscSets";
constexpr const char* const GameList::SETTING_KEY_GRID_VIEW = "GameListGridView";
constexpr const char* const GameList::SETTING_KEY_FULLSCREENUI_GRID_VIEW = "GameListFullscreenUIGridView";
constexpr const char* const GameList::SETTING_KEY_COVER_TITLES = "GameListCoverTitles";
GameList::Entry::Entry() = default;
GameList::Entry::~Entry() = default;
std::string_view GameList::Entry::GetDisplayTitle(bool localized) const
{
// if custom title is present, use that for display too
return !title.empty() ? std::string_view(title) :
(IsDiscSet() ? dbentry->disc_set->GetDisplayTitle(localized) :
(dbentry ? dbentry->GetDisplayTitle(localized) : std::string_view()));
}
std::string_view GameList::Entry::GetSortTitle() const
{
// if custom title is present, use that for sorting too
return !title.empty() ?
std::string_view(title) :
(IsDiscSet() ? dbentry->disc_set->GetSortTitle() : (dbentry ? dbentry->GetSortTitle() : std::string_view()));
}
std::string_view GameList::Entry::GetSaveTitle() const
{
// if custom title is present, use that for save folder too
return !title.empty() ?
std::string_view(title) :
(IsDiscSet() ? dbentry->disc_set->GetSaveTitle() : (dbentry ? dbentry->GetSaveTitle() : std::string_view()));
}
std::string_view GameList::Entry::GetLanguageIcon() const
{
std::string_view ret;
if (custom_language != GameDatabase::Language::MaxCount)
ret = GameDatabase::GetLanguageName(custom_language);
else if (dbentry)
ret = dbentry->GetLanguageFlagName(region);
else
ret = Settings::GetDiscRegionName(region);
return ret;
}
TinyString GameList::Entry::GetLanguageIconName() const
{
return GameDatabase::GetLanguageFlagResourceName(GetLanguageIcon());
}
TinyString GameList::Entry::GetCompatibilityIconFileName() const
{
return TinyString::from_format(
"images/star-{}.svg",
static_cast<u32>(dbentry ? dbentry->compatibility : GameDatabase::CompatibilityRating::Unknown));
}
std::string GameList::Entry::GetReleaseDateString() const
{
std::string ret;
if (!dbentry || dbentry->release_date == 0)
ret = TRANSLATE_STR("GameList", "Unknown");
else
ret = Host::FormatDate(static_cast<std::time_t>(dbentry->release_date), false);
return ret;
}
bool GameList::Entry::IsGame() const
{
return (type != EntryType::PSF && type != EntryType::AudioCD && !serial.empty());
}
const char* GameList::GetEntryTypeName(EntryType type)
{
static std::array<const char*, static_cast<int>(EntryType::MaxCount)> names = {{
@@ -191,22 +272,223 @@ const char* GameList::GetEntryTypeDisplayName(EntryType type)
return Host::TranslateToCString("GameList", names[static_cast<size_t>(type)], "EntryType");
}
static constexpr std::array<const char*, static_cast<size_t>(GameList::Column::MaxCount)> s_column_names = {{
"Type",
"Serial",
"Title",
"FileTitle",
"Developer",
"Publisher",
"Genre",
"Year",
"Players",
"TimePlayed",
"LastPlayed",
"Size",
"DataSize",
"Region",
"Achievements",
"Compatibility",
}};
static constexpr std::array<const char*, static_cast<size_t>(GameList::Column::MaxCount)> s_column_display_names = {{
TRANSLATE_DISAMBIG_NOOP("GameList", "Type", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Serial", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Title", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "File Title", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Developer", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Publisher", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Genre", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Year", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Players", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Time Played", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Last Played", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Size", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Data Size", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Region", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Achievements", "Column"),
TRANSLATE_DISAMBIG_NOOP("GameList", "Compatibility", "Column"),
}};
const char* GameList::GetColumnName(Column column)
{
return (static_cast<size_t>(column) < s_column_names.size()) ? s_column_names[static_cast<size_t>(column)] : "";
}
const char* GameList::GetColumnDisplayName(Column column)
{
return (static_cast<size_t>(column) < s_column_display_names.size()) ?
Host::TranslateToCString("GameList", s_column_display_names[static_cast<size_t>(column)], "Column") :
"";
}
std::optional<GameList::Column> GameList::ParseColumnName(std::string_view name)
{
for (size_t i = 0; i < s_column_names.size(); i++)
{
if (name == s_column_names[i])
return static_cast<Column>(i);
}
return std::nullopt;
}
bool GameList::CompareEntryLessThan(const Entry* left, const Entry* right, Column column)
{
switch (column)
{
case Column::Type:
{
const GameList::EntryType lst = left->GetSortType();
const GameList::EntryType rst = right->GetSortType();
if (lst == rst)
return CompareEntryTitlesLessThan(left, right);
return (static_cast<int>(lst) < static_cast<int>(rst));
}
case Column::Serial:
{
const int res = StringUtil::CompareNoCase(left->serial, right->serial);
return (res == 0) ? CompareEntryTitlesLessThan(left, right) : (res < 0);
}
case Column::Title:
{
return CompareEntryTitlesLessThan(left, right);
}
case Column::FileTitle:
{
const std::string_view file_title_left = Path::GetFileTitle(left->path);
const std::string_view file_title_right = Path::GetFileTitle(right->path);
const int res = StringUtil::CompareNoCase(file_title_left, file_title_right);
return (res == 0) ? CompareEntryTitlesLessThan(left, right) : (res < 0);
}
case Column::Developer:
{
const int res = StringUtil::CompareNoCase(left->dbentry ? left->dbentry->developer : std::string_view(),
right->dbentry ? right->dbentry->developer : std::string_view());
return (res == 0) ? CompareEntryTitlesLessThan(left, right) : (res < 0);
}
case Column::Publisher:
{
const int res = StringUtil::CompareNoCase(left->dbentry ? left->dbentry->publisher : std::string_view(),
right->dbentry ? right->dbentry->publisher : std::string_view());
return (res == 0) ? CompareEntryTitlesLessThan(left, right) : (res < 0);
}
case Column::Genre:
{
const int res = StringUtil::CompareNoCase(left->dbentry ? left->dbentry->genre : std::string_view(),
right->dbentry ? right->dbentry->genre : std::string_view());
return (res == 0) ? CompareEntryTitlesLessThan(left, right) : (res < 0);
}
case Column::Year:
{
const u64 ldate = left->dbentry ? left->dbentry->release_date : 0;
const u64 rdate = right->dbentry ? right->dbentry->release_date : 0;
return (ldate == rdate) ? CompareEntryTitlesLessThan(left, right) : (ldate < rdate);
}
case Column::Players:
{
const u8 left_players = left->dbentry ? ((left->dbentry->min_players << 4) + left->dbentry->max_players) : 0;
const u8 right_players = right->dbentry ? ((right->dbentry->min_players << 4) + right->dbentry->max_players) : 0;
return (left_players == right_players) ? CompareEntryTitlesLessThan(left, right) : (left_players < right_players);
}
case Column::TimePlayed:
{
return (left->total_played_time == right->total_played_time) ?
CompareEntryTitlesLessThan(left, right) :
(left->total_played_time < right->total_played_time);
}
case Column::LastPlayed:
{
return (left->last_played_time == right->last_played_time) ? CompareEntryTitlesLessThan(left, right) :
(left->last_played_time < right->last_played_time);
}
case Column::FileSize:
{
return (left->file_size == right->file_size) ? CompareEntryTitlesLessThan(left, right) :
(left->file_size < right->file_size);
}
case Column::DataSize:
{
return (left->uncompressed_size == right->uncompressed_size) ?
CompareEntryTitlesLessThan(left, right) :
(left->uncompressed_size < right->uncompressed_size);
}
case Column::Region:
{
return (left->region == right->region) ? CompareEntryTitlesLessThan(left, right) :
(static_cast<int>(left->region) < static_cast<int>(right->region));
}
case Column::Achievements:
{
// sort by unlock percentage
const float unlock_left =
(left->num_achievements > 0) ?
(static_cast<float>(std::max(left->unlocked_achievements, left->unlocked_achievements_hc)) /
static_cast<float>(left->num_achievements)) :
0;
const float unlock_right =
(right->num_achievements > 0) ?
(static_cast<float>(std::max(right->unlocked_achievements, right->unlocked_achievements_hc)) /
static_cast<float>(right->num_achievements)) :
0;
if (std::abs(unlock_left - unlock_right) < 0.0001f)
{
// order by achievement count
if (left->num_achievements == right->num_achievements)
return CompareEntryTitlesLessThan(left, right);
return (left->num_achievements < right->num_achievements);
}
return (unlock_left < unlock_right);
}
case Column::Compatibilty:
{
const GameDatabase::CompatibilityRating left_compatibility =
left->dbentry ? left->dbentry->compatibility : GameDatabase::CompatibilityRating::Unknown;
const GameDatabase::CompatibilityRating right_compatibility =
right->dbentry ? right->dbentry->compatibility : GameDatabase::CompatibilityRating::Unknown;
return (left_compatibility == right_compatibility) ? CompareEntryTitlesLessThan(left, right) :
(left_compatibility < right_compatibility);
}
default:
return false;
}
}
bool GameList::CompareEntryTitlesLessThan(const Entry* left, const Entry* right)
{
const s32 res = StringUtil::CompareNoCase(left->GetSortTitle(), right->GetSortTitle());
if (res != 0)
return (res < 0);
// Fallback to path compare if titles are the same.
return (left->path < right->path);
}
bool GameList::IsGameListLoaded()
{
const std::unique_lock lock(s_state.mutex);
return (s_state.game_list_loaded != ListState::Unloaded);
}
bool GameList::ShouldShowLocalizedTitles()
{
return Core::GetBaseBoolSettingValue("UI", "GameListShowLocalizedTitles", true);
}
bool GameList::PreferAchievementGameBadgesForIcons()
{
return Core::GetBaseBoolSettingValue("UI", "GameListPreferAchievementGameBadgesForIcons", false);
}
bool GameList::IsScannableFilename(std::string_view path)
{
// we don't scan bin files because they'll duplicate with cue, same with img for ccd
@@ -1424,72 +1706,6 @@ std::string GameList::GetNewCoverImagePathForEntry(const Entry* entry, const cha
return Path::Combine(EmuFolders::Covers, Path::SanitizeFileName(filename));
}
std::string_view GameList::Entry::GetDisplayTitle(bool localized) const
{
// if custom title is present, use that for display too
return !title.empty() ? std::string_view(title) :
(IsDiscSet() ? dbentry->disc_set->GetDisplayTitle(localized) :
(dbentry ? dbentry->GetDisplayTitle(localized) : std::string_view()));
}
std::string_view GameList::Entry::GetSortTitle() const
{
// if custom title is present, use that for sorting too
return !title.empty() ?
std::string_view(title) :
(IsDiscSet() ? dbentry->disc_set->GetSortTitle() : (dbentry ? dbentry->GetSortTitle() : std::string_view()));
}
std::string_view GameList::Entry::GetSaveTitle() const
{
// if custom title is present, use that for save folder too
return !title.empty() ?
std::string_view(title) :
(IsDiscSet() ? dbentry->disc_set->GetSaveTitle() : (dbentry ? dbentry->GetSaveTitle() : std::string_view()));
}
std::string_view GameList::Entry::GetLanguageIcon() const
{
std::string_view ret;
if (custom_language != GameDatabase::Language::MaxCount)
ret = GameDatabase::GetLanguageName(custom_language);
else if (dbentry)
ret = dbentry->GetLanguageFlagName(region);
else
ret = Settings::GetDiscRegionName(region);
return ret;
}
TinyString GameList::Entry::GetLanguageIconName() const
{
return GameDatabase::GetLanguageFlagResourceName(GetLanguageIcon());
}
TinyString GameList::Entry::GetCompatibilityIconFileName() const
{
return TinyString::from_format(
"images/star-{}.svg",
static_cast<u32>(dbentry ? dbentry->compatibility : GameDatabase::CompatibilityRating::Unknown));
}
std::string GameList::Entry::GetReleaseDateString() const
{
std::string ret;
if (!dbentry || dbentry->release_date == 0)
ret = TRANSLATE_STR("GameList", "Unknown");
else
ret = Host::FormatDate(static_cast<std::time_t>(dbentry->release_date), false);
return ret;
}
bool GameList::Entry::IsGame() const
{
return (type != EntryType::PSF && type != EntryType::AudioCD && !serial.empty());
}
std::string GameList::GetPlayedTimePath()
{
return Path::Combine(EmuFolders::DataRoot, "playtime.dat");
@@ -2140,8 +2356,12 @@ std::string GameList::GetGameIconPath(std::string_view custom_title, std::string
if (achievements_game_id != 0)
{
fallback_path = Achievements::GetGameBadgeURL(achievements_game_id);
if (!fallback_path.empty() && PreferAchievementGameBadgesForIcons())
if (!fallback_path.empty() &&
Core::GetBaseBoolSettingValue(UI_SETTING_SECTION, SETTING_KEY_PREFER_ACHIEVEMENT_CONTENT_ICONS,
DEFAULT_PREFER_ACHIEVEMENT_CONTENT_ICONS))
{
return (ret = std::move(fallback_path));
}
}
if (serial.empty())
+49 -3
View File
@@ -31,8 +31,33 @@ enum class EntryType : u8
MaxCount
};
enum class Column : u8
{
Type,
Serial,
Title,
FileTitle,
Developer,
Publisher,
Genre,
Year,
Players,
TimePlayed,
LastPlayed,
FileSize,
DataSize,
Region,
Achievements,
Compatibilty,
MaxCount,
};
struct Entry
{
Entry();
~Entry();
EntryType type = EntryType::MaxCount;
DiscRegion region = DiscRegion::Other;
@@ -102,6 +127,12 @@ using EntryList = std::vector<Entry>;
const char* GetEntryTypeName(EntryType type);
const char* GetEntryTypeDisplayName(EntryType type);
const char* GetColumnName(Column column);
const char* GetColumnDisplayName(Column column);
std::optional<Column> ParseColumnName(std::string_view name);
bool CompareEntryLessThan(const Entry* left, const Entry* right, Column column);
bool CompareEntryTitlesLessThan(const Entry* left, const Entry* right);
bool IsScannableFilename(std::string_view path);
/// Populates a game list entry struct with information from the specified path.
@@ -119,7 +150,6 @@ const Entry* GetFirstDiscSetMember(const GameDatabase::DiscSetEntry* dsentry);
size_t GetEntryCount();
bool IsGameListLoaded();
bool ShouldShowLocalizedTitles();
/// Returns true if the specified path should not have game properties saved.
bool CanEditGameSettingsForPath(const std::string_view path, const std::string_view serial);
@@ -193,8 +223,24 @@ void UpdateAchievementData(std::span<const u8, 16> hash, u32 game_id, u32 num_ac
u32 num_unlocked_hardcore);
void UpdateAllAchievementData();
/// Accesses achievement game badges. Assumes the lock is held.
bool PreferAchievementGameBadgesForIcons();
// Setting keys
extern const char* const UI_SETTING_SECTION;
extern const char* const SETTING_KEY_LOCALIZED_TITLES;
extern const char* const SETTING_KEY_SORT_COLUMN;
extern const char* const SETTING_KEY_SORT_REVERSED;
extern const char* const SETTING_KEY_PREFER_ACHIEVEMENT_CONTENT_ICONS;
extern const char* const SETTING_KEY_MERGE_DISC_SETS;
extern const char* const SETTING_KEY_GRID_VIEW;
extern const char* const SETTING_KEY_FULLSCREENUI_GRID_VIEW;
extern const char* const SETTING_KEY_COVER_TITLES;
inline constexpr bool DEFAULT_LOCALIZED_TITLES = true;
inline constexpr Column DEFAULT_SORT_COLUMN = Column::Title;
inline constexpr bool DEFAULT_SORT_REVERSED = false;
inline constexpr bool DEFAULT_PREFER_ACHIEVEMENT_CONTENT_ICONS = false;
inline constexpr bool DEFAULT_MERGE_DISC_SETS = true;
inline constexpr bool DEFAULT_GRID_VIEW = false;
inline constexpr bool DEFAULT_FULLSCREENUI_GRID_VIEW = true;
inline constexpr bool DEFAULT_COVER_TITLES = true;
} // namespace GameList
-1
View File
@@ -162,7 +162,6 @@ std::span<const char* const> Settings::GetSectionSaveOrder()
"Cheats",
"Main",
"UI",
"GameListTableView",
"AutoUpdater",
"Folders",
"GameList",
+6 -4
View File
@@ -4175,8 +4175,9 @@ void System::UpdateRunningGame(const std::string& path, CDImage* image, bool boo
s_state.running_game_entry = GameDatabase::GetEntryForSerial(s_state.running_game_serial);
if (s_state.running_game_entry && s_state.running_game_title.empty())
{
s_state.running_game_title =
s_state.running_game_entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles());
s_state.running_game_title = s_state.running_game_entry->GetDisplayTitle(
Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES,
GameList::DEFAULT_LOCALIZED_TITLES));
}
else if (s_state.running_game_title.empty())
{
@@ -4204,8 +4205,9 @@ void System::UpdateRunningGame(const std::string& path, CDImage* image, bool boo
if (s_state.running_game_title.empty())
{
s_state.running_game_title =
s_state.running_game_entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles());
s_state.running_game_title = s_state.running_game_entry->GetDisplayTitle(
Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES,
GameList::DEFAULT_LOCALIZED_TITLES));
}
}
else
+145 -281
View File
@@ -83,25 +83,21 @@ static const char* SUPPORTED_FORMATS_STRING =
".chd (Compressed Hunks of Data)\n"
".pbp (PlayStation Portable, Only Decrypted)");
static constexpr std::array<const char*, GameListModel::Column_Count> s_column_names = {{
QT_TRANSLATE_NOOP("GameListModel", "Icon"),
QT_TRANSLATE_NOOP("GameListModel", "Serial"),
QT_TRANSLATE_NOOP("GameListModel", "Title"),
QT_TRANSLATE_NOOP("GameListModel", "File Title"),
QT_TRANSLATE_NOOP("GameListModel", "Developer"),
QT_TRANSLATE_NOOP("GameListModel", "Publisher"),
QT_TRANSLATE_NOOP("GameListModel", "Genre"),
QT_TRANSLATE_NOOP("GameListModel", "Year"),
QT_TRANSLATE_NOOP("GameListModel", "Players"),
QT_TRANSLATE_NOOP("GameListModel", "Time Played"),
QT_TRANSLATE_NOOP("GameListModel", "Last Played"),
QT_TRANSLATE_NOOP("GameListModel", "Size"),
QT_TRANSLATE_NOOP("GameListModel", "Data Size"),
QT_TRANSLATE_NOOP("GameListModel", "Region"),
QT_TRANSLATE_NOOP("GameListModel", "Achievements"),
QT_TRANSLATE_NOOP("GameListModel", "Compatibility"),
"Cover", // Do not translate.
}};
static_assert(static_cast<int>(GameList::Column::Type) == GameListModel::Column_Icon);
static_assert(static_cast<int>(GameList::Column::Serial) == GameListModel::Column_Serial);
static_assert(static_cast<int>(GameList::Column::Title) == GameListModel::Column_Title);
static_assert(static_cast<int>(GameList::Column::FileTitle) == GameListModel::Column_FileTitle);
static_assert(static_cast<int>(GameList::Column::Developer) == GameListModel::Column_Developer);
static_assert(static_cast<int>(GameList::Column::Publisher) == GameListModel::Column_Publisher);
static_assert(static_cast<int>(GameList::Column::Genre) == GameListModel::Column_Genre);
static_assert(static_cast<int>(GameList::Column::Year) == GameListModel::Column_Year);
static_assert(static_cast<int>(GameList::Column::Players) == GameListModel::Column_Players);
static_assert(static_cast<int>(GameList::Column::TimePlayed) == GameListModel::Column_TimePlayed);
static_assert(static_cast<int>(GameList::Column::LastPlayed) == GameListModel::Column_LastPlayed);
static_assert(static_cast<int>(GameList::Column::FileSize) == GameListModel::Column_FileSize);
static_assert(static_cast<int>(GameList::Column::DataSize) == GameListModel::Column_DataSize);
static_assert(static_cast<int>(GameList::Column::Region) == GameListModel::Column_Region);
static_assert(static_cast<int>(GameList::Column::Achievements) == GameListModel::Column_Achievements);
static void resizeImage(QImage* image, const QSize& expected_size)
{
@@ -222,31 +218,11 @@ static QString sizeToString(s64 size)
QCoreApplication::translate("GameList", "Unknown");
}
std::optional<GameListModel::Column> GameListModel::getColumnIdForName(std::string_view name)
{
for (int column = 0; column < Column_Count; column++)
{
if (name == s_column_names[column])
return static_cast<Column>(column);
}
return std::nullopt;
}
const char* GameListModel::getColumnName(Column col)
{
return s_column_names[static_cast<int>(col)];
}
GameListModel::GameListModel(GameListWidget* parent)
: QAbstractTableModel(parent), m_device_pixel_ratio(parent->devicePixelRatio()),
m_icon_pixmap_cache(MIN_COVER_CACHE_SIZE)
{
m_cover_scale = Core::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", DEFAULT_COVER_SCALE);
m_icon_size = Core::GetBaseIntSettingValue("UI", "GameListIconSize", GAME_ICON_DEFAULT_SIZE);
m_show_localized_titles = GameList::ShouldShowLocalizedTitles();
m_show_titles_for_covers = Core::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true);
m_show_game_icons = Core::GetBaseBoolSettingValue("UI", "GameListShowGameIcons", true);
reloadSettings();
loadCommonImages();
loadCoverScaleDependentPixmaps();
@@ -259,6 +235,30 @@ GameListModel::GameListModel(GameListWidget* parent)
GameListModel::~GameListModel() = default;
void GameListModel::loadSettings()
{
m_cover_scale =
Core::GetBaseFloatSettingValue(GameList::UI_SETTING_SECTION, "GameListCoverArtScale", DEFAULT_COVER_SCALE);
m_icon_size = Core::GetBaseIntSettingValue(GameList::UI_SETTING_SECTION, "GameListIconSize", GAME_ICON_DEFAULT_SIZE);
m_show_localized_titles = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES);
m_show_titles_for_covers = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_COVER_TITLES, GameList::DEFAULT_COVER_TITLES);
m_show_game_icons = Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "GameListShowGameIcons", true);
}
void GameListModel::reloadSettings()
{
setCoverScale(
Core::GetBaseFloatSettingValue(GameList::UI_SETTING_SECTION, "GameListCoverArtScale", DEFAULT_COVER_SCALE));
setIconSize(Core::GetBaseIntSettingValue(GameList::UI_SETTING_SECTION, "GameListIconSize", GAME_ICON_DEFAULT_SIZE));
setShowLocalizedTitles(Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES));
setShowCoverTitles(Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_COVER_TITLES,
GameList::DEFAULT_COVER_TITLES));
setShowGameIcons(Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "GameListShowGameIcons", true));
}
bool GameListModel::getShowLocalizedTitles() const
{
return m_show_localized_titles;
@@ -303,9 +303,6 @@ void GameListModel::setIconSize(int size)
m_icon_size = size;
Core::SetBaseIntSettingValue("UI", "GameListIconSize", size);
Host::CommitBaseSettingChanges();
emit iconSizeChanged(m_icon_size);
// Might look odd, but this is needed to force the section sizes to invalidate
@@ -333,9 +330,10 @@ void GameListModel::setCoverScale(float scale)
m_cover_pixmap_cache.Apply(
[](const std::string&, CoverPixmapCacheEntry& entry) { entry.scale = entry.is_loading ? 0.0f : entry.scale; });
Core::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", scale);
Host::CommitBaseSettingChanges();
updateCoverScale();
loadCoverScaleDependentPixmaps();
emit coverScaleChanged(m_cover_scale);
emit dataChanged(index(0, Column_Cover), index(rowCount() - 1, Column_Cover),
{Qt::DecorationRole, Qt::FontRole, Qt::SizeHintRole});
}
void GameListModel::loadCoverScaleDependentPixmaps()
@@ -368,14 +366,6 @@ void GameListModel::loadCoverScaleDependentPixmaps()
}
}
void GameListModel::updateCoverScale()
{
loadCoverScaleDependentPixmaps();
emit coverScaleChanged(m_cover_scale);
emit dataChanged(index(0, Column_Cover), index(rowCount() - 1, Column_Cover),
{Qt::DecorationRole, Qt::FontRole, Qt::SizeHintRole});
}
void GameListModel::updateCacheSize(int num_rows, int num_columns, QSortFilterProxyModel* const sort_model,
int top_left_row)
{
@@ -1108,11 +1098,10 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant ret;
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section < Column_Count)
ret = QCoreApplication::translate("GameListModel", s_column_names[static_cast<u32>(section)]);
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= 0 && section <= Column_LastVisible)
return QString::fromUtf8(GameList::GetColumnDisplayName(static_cast<GameList::Column>(section)));
return ret;
return {};
}
const QPixmap& GameListModel::getNoAchievementsPixmap() const
@@ -1162,16 +1151,6 @@ void GameListModel::refresh()
endResetModel();
}
bool GameListModel::titlesLessThan(const GameList::Entry* left, const GameList::Entry* right) const
{
const s32 res = StringUtil::CompareNoCase(left->GetSortTitle(), right->GetSortTitle());
if (res != 0)
return (res < 0);
// Fallback to path compare if titles are the same.
return (left->path < right->path);
}
bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& right_index, int column) const
{
if (!left_index.isValid() || !right_index.isValid())
@@ -1188,7 +1167,7 @@ bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& r
if (!left || !right)
return false;
return lessThan(left, right, column);
return GameList::CompareEntryLessThan(left, right, static_cast<GameList::Column>(column));
}
else
{
@@ -1198,169 +1177,7 @@ bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& r
if (!left || !right)
return false;
return lessThan(left, right, column);
}
}
bool GameListModel::lessThan(const GameList::Entry* left, const GameList::Entry* right, int column) const
{
switch (column)
{
case Column_Icon:
{
const GameList::EntryType lst = left->GetSortType();
const GameList::EntryType rst = right->GetSortType();
if (lst == rst)
return titlesLessThan(left, right);
return (static_cast<int>(lst) < static_cast<int>(rst));
}
case Column_Serial:
{
if (left->serial == right->serial)
return titlesLessThan(left, right);
return (StringUtil::Strcasecmp(left->serial.c_str(), right->serial.c_str()) < 0);
}
case Column_Title:
{
return titlesLessThan(left, right);
}
case Column_FileTitle:
{
const std::string_view file_title_left = Path::GetFileTitle(left->path);
const std::string_view file_title_right = Path::GetFileTitle(right->path);
if (file_title_left == file_title_right)
return titlesLessThan(left, right);
const std::size_t smallest = std::min(file_title_left.size(), file_title_right.size());
return (StringUtil::Strncasecmp(file_title_left.data(), file_title_right.data(), smallest) < 0);
}
case Column_Region:
{
if (left->region == right->region)
return titlesLessThan(left, right);
return (static_cast<int>(left->region) < static_cast<int>(right->region));
}
case Column_Compatibility:
{
const GameDatabase::CompatibilityRating left_compatibility =
left->dbentry ? left->dbentry->compatibility : GameDatabase::CompatibilityRating::Unknown;
const GameDatabase::CompatibilityRating right_compatibility =
right->dbentry ? right->dbentry->compatibility : GameDatabase::CompatibilityRating::Unknown;
if (left_compatibility == right_compatibility)
return titlesLessThan(left, right);
return (static_cast<int>(left_compatibility) < static_cast<int>(right_compatibility));
}
case Column_FileSize:
{
if (left->file_size == right->file_size)
return titlesLessThan(left, right);
return (left->file_size < right->file_size);
}
case Column_DataSize:
{
if (left->uncompressed_size == right->uncompressed_size)
return titlesLessThan(left, right);
return (left->uncompressed_size < right->uncompressed_size);
}
case Column_Genre:
{
const int compres =
StringUtil::CompareNoCase(left->dbentry ? std::string_view(left->dbentry->genre) : std::string_view(),
right->dbentry ? std::string_view(right->dbentry->genre) : std::string_view());
return (compres == 0) ? titlesLessThan(left, right) : (compres < 0);
}
case Column_Developer:
{
const int compres =
StringUtil::CompareNoCase(left->dbentry ? std::string_view(left->dbentry->developer) : std::string_view(),
right->dbentry ? std::string_view(right->dbentry->developer) : std::string_view());
return (compres == 0) ? titlesLessThan(left, right) : (compres < 0);
}
case Column_Publisher:
{
const int compres =
StringUtil::CompareNoCase(left->dbentry ? std::string_view(left->dbentry->publisher) : std::string_view(),
right->dbentry ? std::string_view(right->dbentry->publisher) : std::string_view());
return (compres == 0) ? titlesLessThan(left, right) : (compres < 0);
}
case Column_Year:
{
const u64 ldate = left->dbentry ? left->dbentry->release_date : 0;
const u64 rdate = right->dbentry ? right->dbentry->release_date : 0;
if (ldate == rdate)
return titlesLessThan(left, right);
return (ldate < rdate);
}
case Column_TimePlayed:
{
if (left->total_played_time == right->total_played_time)
return titlesLessThan(left, right);
return (left->total_played_time < right->total_played_time);
}
case Column_LastPlayed:
{
if (left->last_played_time == right->last_played_time)
return titlesLessThan(left, right);
return (left->last_played_time < right->last_played_time);
}
case Column_Players:
{
const u8 left_players = left->dbentry ? ((left->dbentry->min_players << 4) + left->dbentry->max_players) : 0;
const u8 right_players = right->dbentry ? ((right->dbentry->min_players << 4) + right->dbentry->max_players) : 0;
if (left_players == right_players)
return titlesLessThan(left, right);
return (left_players < right_players);
}
case Column_Achievements:
{
// sort by unlock percentage
const float unlock_left =
(left->num_achievements > 0) ?
(static_cast<float>(std::max(left->unlocked_achievements, left->unlocked_achievements_hc)) /
static_cast<float>(left->num_achievements)) :
0;
const float unlock_right =
(right->num_achievements > 0) ?
(static_cast<float>(std::max(right->unlocked_achievements, right->unlocked_achievements_hc)) /
static_cast<float>(right->num_achievements)) :
0;
if (std::abs(unlock_left - unlock_right) < 0.0001f)
{
// order by achievement count
if (left->num_achievements == right->num_achievements)
return titlesLessThan(left, right);
return (left->num_achievements < right->num_achievements);
}
return (unlock_left < unlock_right);
}
default:
return false;
return GameList::CompareEntryLessThan(left, right, static_cast<GameList::Column>(column));
}
}
@@ -1397,11 +1214,17 @@ class GameListSortModel final : public QSortFilterProxyModel
public:
explicit GameListSortModel(GameListModel* parent) : QSortFilterProxyModel(parent), m_model(parent)
{
m_merge_disc_sets = Core::GetBaseBoolSettingValue("UI", "GameListMergeDiscSets", true);
reloadSettings();
}
bool isMergingDiscSets() const { return m_merge_disc_sets; }
void reloadSettings()
{
setMergeDiscSets(Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_MERGE_DISC_SETS,
GameList::DEFAULT_MERGE_DISC_SETS));
}
void setMergeDiscSets(bool enabled)
{
beginFilterChange();
@@ -1856,11 +1679,11 @@ GameListWidget::GameListWidget(QWidget* parent, QAction* action_view_list, QActi
QString::fromUtf8(Settings::GetDiscRegionDisplayName(static_cast<DiscRegion>(region))));
}
m_list_view = new GameListListView(m_model, m_sort_model, m_ui.stack);
m_list_view = new GameListListView(this, m_model, m_sort_model, m_ui.stack);
m_list_view->setAnimateGameIcons(Core::GetBaseBoolSettingValue("UI", "GameListAnimateGameIcons", false));
m_ui.stack->insertWidget(0, m_list_view);
m_grid_view = new GameListGridView(m_model, m_sort_model, m_ui.stack);
m_grid_view = new GameListGridView(this, m_model, m_sort_model, m_ui.stack);
m_grid_view->setItemDelegate(new GameListCoverDelegate(m_grid_view, m_model, m_sort_model));
m_ui.stack->insertWidget(1, m_grid_view);
@@ -1911,7 +1734,9 @@ GameListWidget::GameListWidget(QWidget* parent, QAction* action_view_list, QActi
action_show_localized_titles->setChecked(m_model->getShowLocalizedTitles());
action_show_list_icons->setChecked(m_model->getShowGameIcons());
action_animate_list_icons->setChecked(m_list_view->isAnimatingGameIcons());
action_prefer_achievement_game_icons->setChecked(GameList::PreferAchievementGameBadgesForIcons());
action_prefer_achievement_game_icons->setChecked(
Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_PREFER_ACHIEVEMENT_CONTENT_ICONS,
GameList::DEFAULT_PREFER_ACHIEVEMENT_CONTENT_ICONS));
action_show_grid_titles->setChecked(m_model->getShowCoverTitles());
onIconSizeChanged(m_model->getIconSize());
@@ -1926,6 +1751,18 @@ QString GameListWidget::getSupportedFormatsString()
return tr(SUPPORTED_FORMATS_STRING);
}
void GameListWidget::reloadSettings()
{
m_model->reloadSettings();
m_sort_model->reloadSettings();
m_list_view->loadColumnSortSettings();
m_ui.mergeDiscSets->defaultAction()->setChecked(m_sort_model->isMergingDiscSets());
m_ui.showLocalizedTitles->defaultAction()->setChecked(m_model->getShowLocalizedTitles());
m_ui.showGridTitles->defaultAction()->setChecked(m_model->getShowCoverTitles());
m_grid_view->updateLayout(true);
reloadViewModeFromSettings();
}
bool GameListWidget::isShowingGameList() const
{
return (m_ui.stack->currentIndex() == VIEW_MODE_LIST);
@@ -2185,7 +2022,7 @@ void GameListWidget::showGameList()
if (isShowingGameList() || m_model->rowCount() == 0)
return;
Core::SetBaseBoolSettingValue("UI", "GameListGridView", false);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "GameListGridView", false);
Host::CommitBaseSettingChanges();
setViewMode(VIEW_MODE_LIST);
@@ -2197,7 +2034,7 @@ void GameListWidget::showGameGrid()
if (isShowingGameGrid() || m_model->rowCount() == 0)
return;
Core::SetBaseBoolSettingValue("UI", "GameListGridView", true);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "GameListGridView", true);
Host::CommitBaseSettingChanges();
setViewMode(VIEW_MODE_GRID);
@@ -2205,7 +2042,8 @@ void GameListWidget::showGameGrid()
void GameListWidget::reloadViewModeFromSettings()
{
const bool grid_view = Core::GetBaseBoolSettingValue("UI", "GameListGridView", false);
const bool grid_view = Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_GRID_VIEW,
GameList::DEFAULT_GRID_VIEW);
m_ui.viewGameList->defaultAction()->setChecked(!grid_view);
m_ui.viewGameGrid->defaultAction()->setChecked(grid_view);
@@ -2218,7 +2056,7 @@ void GameListWidget::setMergeDiscSets(bool enabled)
if (m_sort_model->isMergingDiscSets() == enabled)
return;
Core::SetBaseBoolSettingValue("UI", "GameListMergeDiscSets", enabled);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_MERGE_DISC_SETS, enabled);
Host::CommitBaseSettingChanges();
m_sort_model->setMergeDiscSets(enabled);
}
@@ -2228,7 +2066,7 @@ void GameListWidget::setShowLocalizedTitles(bool enabled)
if (m_model->getShowLocalizedTitles() == enabled)
return;
Core::SetBaseBoolSettingValue("UI", "GameListShowLocalizedTitles", enabled);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, enabled);
Host::CommitBaseSettingChanges();
m_model->setShowLocalizedTitles(enabled);
}
@@ -2238,7 +2076,7 @@ void GameListWidget::setShowGameIcons(bool enabled)
if (m_model->getShowGameIcons() == enabled)
return;
Core::SetBaseBoolSettingValue("UI", "GameListShowGameIcons", enabled);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "GameListShowGameIcons", enabled);
Host::CommitBaseSettingChanges();
m_model->setShowGameIcons(enabled);
if (isShowingGameList() && m_list_view->isAnimatingGameIcons())
@@ -2255,7 +2093,7 @@ void GameListWidget::setAnimateGameIcons(bool enabled)
if (m_list_view->isAnimatingGameIcons() == enabled)
return;
Core::SetBaseBoolSettingValue("UI", "GameListAnimateGameIcons", enabled);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "GameListAnimateGameIcons", enabled);
Host::CommitBaseSettingChanges();
m_list_view->setAnimateGameIcons(enabled);
if (isShowingGameList())
@@ -2264,7 +2102,8 @@ void GameListWidget::setAnimateGameIcons(bool enabled)
void GameListWidget::setPreferAchievementGameIcons(bool enabled)
{
Core::SetBaseBoolSettingValue("UI", "GameListPreferAchievementGameBadgesForIcons", enabled);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_PREFER_ACHIEVEMENT_CONTENT_ICONS,
enabled);
Host::CommitBaseSettingChanges();
if (!enabled)
@@ -2278,12 +2117,36 @@ void GameListWidget::setShowCoverTitles(bool enabled)
if (m_model->getShowCoverTitles() == enabled)
return;
Core::SetBaseBoolSettingValue("UI", "GameListShowCoverTitles", enabled);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_COVER_TITLES, enabled);
Host::CommitBaseSettingChanges();
m_model->setShowCoverTitles(enabled);
m_grid_view->updateLayout(false);
}
void GameListWidget::setCoverScale(float scale)
{
if (m_model->getCoverScale() == scale)
return;
Core::SetBaseFloatSettingValue(GameList::UI_SETTING_SECTION, "GameListCoverArtScale", scale);
Host::CommitBaseSettingChanges();
m_model->setCoverScale(scale);
}
void GameListWidget::setIconSize(int size)
{
if (m_model->getIconSize() == size)
return;
Core::SetBaseIntSettingValue(GameList::UI_SETTING_SECTION, "GameListIconSize", size);
Host::CommitBaseSettingChanges();
m_model->setIconSize(size);
m_list_view->updateAnimatedGameIconDelegate();
}
void GameListWidget::setViewMode(int stack_index)
{
if (stack_index == VIEW_MODE_GRID && m_grid_view->isLayoutUpdatedDeferred())
@@ -2343,14 +2206,9 @@ void GameListWidget::showScaleToolTip()
void GameListWidget::onScaleSliderChanged(int value)
{
if (isShowingGameGrid())
{
m_model->setCoverScale(static_cast<float>(value) / 100.0f);
}
setCoverScale(static_cast<float>(value) / 100.0f);
else if (isShowingGameList())
{
m_model->setIconSize(value * GAME_ICON_SIZE_STEP);
m_list_view->updateAnimatedGameIconDelegate();
}
setIconSize(value * GAME_ICON_SIZE_STEP);
if (m_ui.scale->isSliderDown())
showScaleToolTip();
@@ -2419,8 +2277,9 @@ const GameList::Entry* GameListWidget::getSelectedEntry() const
}
}
GameListListView::GameListListView(GameListModel* model, GameListSortModel* sort_model, QWidget* parent)
: QTableView(parent), m_model(model), m_sort_model(sort_model)
GameListListView::GameListListView(GameListWidget* widget, GameListModel* model, GameListSortModel* sort_model,
QWidget* parent)
: QTableView(parent), m_widget(widget), m_model(model), m_sort_model(sort_model)
{
setModel(sort_model);
setSortingEnabled(true);
@@ -2537,12 +2396,12 @@ void GameListListView::updateFixedColumnWidths()
static TinyString getColumnVisibilitySettingsKeyName(int column)
{
return TinyString::from_format("Show{}", GameListModel::getColumnName(static_cast<GameListModel::Column>(column)));
return TinyString::from_format("Show{}", GameList::GetColumnName(static_cast<GameList::Column>(column)));
}
void GameListListView::loadColumnVisibilitySettings()
{
static constexpr std::array<bool, GameListModel::Column_Count> DEFAULT_VISIBILITY = {{
static constexpr std::array DEFAULT_VISIBILITY = {
true, // type
true, // serial
true, // title
@@ -2558,31 +2417,36 @@ void GameListListView::loadColumnVisibilitySettings()
false, // size
true, // region
false, // achievements
false // compatibility
}};
false, // compatibility
false, // cover, unused
};
static_assert(std::size(DEFAULT_VISIBILITY) == GameListModel::Column_Count);
for (int column = 0; column < GameListModel::Column_Count; column++)
for (int column = 0; column <= GameListModel::Column_LastVisible; column++)
{
const bool visible = Core::GetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column),
DEFAULT_VISIBILITY[column]);
const bool visible = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, getColumnVisibilitySettingsKeyName(column), DEFAULT_VISIBILITY[column]);
setColumnHidden(column, !visible);
}
setColumnHidden(GameListModel::Column_Cover, true);
}
void GameListListView::loadColumnSortSettings()
{
const GameListModel::Column DEFAULT_SORT_COLUMN = GameListModel::Column_Icon;
const bool DEFAULT_SORT_DESCENDING = false;
const GameListModel::Column sort_column =
GameListModel::getColumnIdForName(Core::GetBaseStringSettingValue("GameListTableView", "SortColumn"))
.value_or(DEFAULT_SORT_COLUMN);
const bool sort_descending =
Core::GetBaseBoolSettingValue("GameListTableView", "SortDescending", DEFAULT_SORT_DESCENDING);
const GameList::Column sort_column =
GameList::ParseColumnName(
Core::GetBaseStringSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_SORT_COLUMN))
.value_or(GameList::DEFAULT_SORT_COLUMN);
const bool sort_descending = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_SORT_REVERSED, GameList::DEFAULT_SORT_REVERSED);
const int sort_column_index = static_cast<int>(sort_column);
const Qt::SortOrder sort_order = sort_descending ? Qt::DescendingOrder : Qt::AscendingOrder;
m_sort_model->sort(sort_column, sort_order);
m_sort_model->sort(sort_column_index, sort_order);
if (QHeaderView* hv = horizontalHeader())
hv->setSortIndicator(sort_column, sort_order);
{
const QSignalBlocker sb(hv);
hv->setSortIndicator(sort_column_index, sort_order);
}
}
void GameListListView::saveColumnSortSettings()
@@ -2590,13 +2454,13 @@ void GameListListView::saveColumnSortSettings()
const int sort_column = horizontalHeader()->sortIndicatorSection();
const bool sort_descending = (horizontalHeader()->sortIndicatorOrder() == Qt::DescendingOrder);
if (sort_column >= 0 && sort_column < GameListModel::Column_Count)
if (sort_column >= 0 && sort_column <= GameListModel::Column_LastVisible)
{
Core::SetBaseStringSettingValue("GameListTableView", "SortColumn",
GameListModel::getColumnName(static_cast<GameListModel::Column>(sort_column)));
Core::SetBaseStringSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_SORT_COLUMN,
GameList::GetColumnName(static_cast<GameList::Column>(sort_column)));
}
Core::SetBaseBoolSettingValue("GameListTableView", "SortDescending", sort_descending);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_SORT_REVERSED, sort_descending);
Host::CommitBaseSettingChanges();
}
@@ -2607,7 +2471,7 @@ void GameListListView::setAndSaveColumnHidden(int column, bool hidden)
return;
setColumnHidden(column, hidden);
Core::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column), !hidden);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, getColumnVisibilitySettingsKeyName(column), !hidden);
Host::CommitBaseSettingChanges();
}
@@ -2632,8 +2496,7 @@ void GameListListView::onHeaderContextMenuRequested(const QPoint& point)
void GameListListView::adjustIconSize(int delta)
{
const int new_size = std::clamp(m_model->getIconSize() + delta, GAME_ICON_MIN_SIZE, GAME_ICON_MAX_SIZE);
m_model->setIconSize(new_size);
updateAnimatedGameIconDelegate();
m_widget->setIconSize(new_size);
}
bool GameListListView::isAnimatingGameIcons() const
@@ -2704,8 +2567,9 @@ void GameListListView::clearAnimatedGameIconDelegate()
m_animated_icon_row = -1;
}
GameListGridView::GameListGridView(GameListModel* model, GameListSortModel* sort_model, QWidget* parent)
: QListView(parent), m_model(model), m_sort_model(sort_model)
GameListGridView::GameListGridView(GameListWidget* widget, GameListModel* model, GameListSortModel* sort_model,
QWidget* parent)
: QListView(parent), m_widget(widget), m_model(model), m_sort_model(sort_model)
{
setModel(sort_model);
setModelColumn(GameListModel::Column_Cover);
@@ -2752,7 +2616,7 @@ void GameListGridView::resizeEvent(QResizeEvent* e)
void GameListGridView::adjustZoom(float delta)
{
const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_COVER_SCALE, MAX_COVER_SCALE);
m_model->setCoverScale(new_scale);
m_widget->setCoverScale(new_scale);
}
void GameListGridView::updateLayout(bool disable_defer)
+11 -9
View File
@@ -64,9 +64,6 @@ public:
Column_LastVisible = Column_Compatibility,
};
static std::optional<Column> getColumnIdForName(std::string_view name);
static const char* getColumnName(Column col);
explicit GameListModel(GameListWidget* parent);
~GameListModel();
@@ -89,10 +86,10 @@ public:
void refresh();
void reloadThemeSpecificImages();
bool titlesLessThan(const GameList::Entry* left, const GameList::Entry* right) const;
bool lessThan(const GameList::Entry* left, const GameList::Entry* right, int column) const;
bool lessThan(const QModelIndex& left_index, const QModelIndex& right_index, int column) const;
void reloadSettings();
bool getShowLocalizedTitles() const;
void setShowLocalizedTitles(bool enabled);
@@ -142,9 +139,9 @@ private:
void rowsChanged(const QList<int>& rows);
void loadSettings();
void loadCommonImages();
void loadSizeDependentPixmaps();
void updateCoverScale();
void loadCoverScaleDependentPixmaps();
void loadOrGenerateCover(const GameList::Entry* ge);
void coverLoaded(const std::string& path, const QImage& image, float scale);
@@ -192,13 +189,14 @@ class GameListListView final : public QTableView
Q_OBJECT
public:
GameListListView(GameListModel* model, GameListSortModel* sort_model, QWidget* parent);
GameListListView(GameListWidget* widget, GameListModel* model, GameListSortModel* sort_model, QWidget* parent);
~GameListListView() override;
QFontMetrics fontMetricsForHorizontalHeader() const;
void setFixedColumnWidth(const QFontMetrics& fm, int column, int str_width);
void setAndSaveColumnHidden(int column, bool hidden);
void updateFixedColumnWidths();
void loadColumnSortSettings();
void adjustIconSize(int delta);
@@ -212,11 +210,11 @@ protected:
private:
void loadColumnVisibilitySettings();
void loadColumnSortSettings();
void onHeaderContextMenuRequested(const QPoint& point);
void saveColumnSortSettings();
GameListWidget* m_widget = nullptr;
GameListModel* m_model = nullptr;
GameListSortModel* m_sort_model = nullptr;
@@ -229,7 +227,7 @@ class GameListGridView final : public QListView
Q_OBJECT
public:
GameListGridView(GameListModel* model, GameListSortModel* sort_model, QWidget* parent);
GameListGridView(GameListWidget* widget, GameListModel* model, GameListSortModel* sort_model, QWidget* parent);
~GameListGridView() override;
ALWAYS_INLINE bool isLayoutUpdatedDeferred() const { return m_layout_update_deferred; }
@@ -246,6 +244,7 @@ protected:
void resizeEvent(QResizeEvent* e) override;
private:
GameListWidget* m_widget = nullptr;
GameListModel* m_model = nullptr;
GameListSortModel* m_sort_model = nullptr;
int m_horizontal_offset = 0;
@@ -268,6 +267,7 @@ public:
ALWAYS_INLINE GameListListView* getListView() const { return m_list_view; }
ALWAYS_INLINE GameListGridView* getGridView() const { return m_grid_view; }
void reloadSettings();
void refresh(bool invalidate_cache);
void cancelRefresh();
void setBackgroundPath(const std::string_view path);
@@ -290,6 +290,8 @@ public:
void setAnimateGameIcons(bool enabled);
void setPreferAchievementGameIcons(bool enabled);
void setShowCoverTitles(bool enabled);
void setCoverScale(float scale);
void setIconSize(int size);
void focusSearchWidget();
// Returns translated supported formats string. Formats are separated by newlines.
+10 -9
View File
@@ -36,7 +36,8 @@
using namespace Qt::StringLiterals;
GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, SettingsWindow* dialog, QWidget* parent)
GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, bool localized_titles, SettingsWindow* dialog,
QWidget* parent)
: m_dialog(dialog)
{
m_ui.setupUi(this);
@@ -70,7 +71,7 @@ GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, SettingsWindo
m_ui.customLanguage->addItem(QtUtils::GetIconForLanguage(language_name), QString::fromUtf8(language_name));
}
populateUi(entry);
populateUi(entry, localized_titles);
connect(m_ui.compatibilityComments, &QAbstractButton::clicked, this,
&GameSummaryWidget::onCompatibilityCommentsClicked);
@@ -134,7 +135,7 @@ void GameSummaryWidget::reloadGameSettings()
m_ui.editInputProfile->setEnabled(m_ui.inputProfile->currentIndex() >= 1);
}
void GameSummaryWidget::populateUi(const GameList::Entry* entry)
void GameSummaryWidget::populateUi(const GameList::Entry* entry, bool localized_titles)
{
m_path = entry->path;
@@ -151,7 +152,7 @@ void GameSummaryWidget::populateUi(const GameList::Entry* entry)
{
m_ui.hashes->setText(tr("N/A"));
}
m_ui.title->setText(QtUtils::StringViewToQString(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles())));
m_ui.title->setText(QtUtils::StringViewToQString(entry->GetDisplayTitle(localized_titles)));
m_ui.region->setCurrentIndex(static_cast<int>(entry->region));
m_ui.entryType->setCurrentIndex(static_cast<int>(entry->type));
@@ -169,8 +170,7 @@ void GameSummaryWidget::populateUi(const GameList::Entry* entry)
entry->disc_set_member ? GameList::GetEntryForPath(entry->GetDiscSetEntry()->GetSaveTitle()) : nullptr;
if (disc_set_entry)
{
m_ui.discSetTitle->setText(
QtUtils::StringViewToQString(disc_set_entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles())));
m_ui.discSetTitle->setText(QtUtils::StringViewToQString(disc_set_entry->GetDisplayTitle(localized_titles)));
m_ui.restoreDiscSetTitle->setEnabled(disc_set_entry->has_custom_title);
}
else
@@ -410,7 +410,8 @@ void GameSummaryWidget::setCustomTitle(const std::string& text)
const GameList::Entry* entry = GameList::GetEntryForPath(m_path);
if (entry)
{
const std::string_view title = entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles());
const std::string_view title = entry->GetDisplayTitle(Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES));
m_dialog->setGameTitle(title);
{
@@ -440,8 +441,8 @@ void GameSummaryWidget::setCustomDiscSetTitle(const std::string& text)
GameList::SaveCustomTitleForPath(disc_set_entry->path, text);
const QSignalBlocker sb(m_ui.discSetTitle);
m_ui.discSetTitle->setText(
QtUtils::StringViewToQString(disc_set_entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles())));
m_ui.discSetTitle->setText(QtUtils::StringViewToQString(disc_set_entry->GetDisplayTitle(Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES))));
m_ui.restoreDiscSetTitle->setEnabled(disc_set_entry->has_custom_title);
+2 -2
View File
@@ -29,13 +29,13 @@ class GameSummaryWidget : public QWidget
Q_OBJECT
public:
GameSummaryWidget(const GameList::Entry* entry, SettingsWindow* dialog, QWidget* parent);
GameSummaryWidget(const GameList::Entry* entry, bool localized_titles, SettingsWindow* dialog, QWidget* parent);
~GameSummaryWidget();
void reloadGameSettings();
private:
void populateUi(const GameList::Entry* entry);
void populateUi(const GameList::Entry* entry, bool localized_titles);
void setCustomTitle(const std::string& text);
void setCustomDiscSetTitle(const std::string& text);
void setCustomRegion(int region);
+6 -2
View File
@@ -1462,6 +1462,10 @@ void MainWindow::onFullscreenUIStartedOrStopped(bool running)
s_locals.fullscreen_ui_started = running;
m_ui.actionStartFullscreenUI->setText(running ? tr("Stop Big Picture Mode") : tr("Start Big Picture Mode"));
m_ui.actionToolbarStartFullscreenUI->setText(running ? tr("Exit Big Picture") : tr("Big Picture"));
// If big picture was exited, then we should refresh the game list settings because they may have changed.
if (!running && !m_is_closing && !QtHost::InBatchMode())
m_game_list_widget->reloadSettings();
}
void MainWindow::onCloseGameActionTriggered()
@@ -3344,9 +3348,9 @@ void MainWindow::onAchievementsLoginSuccess(const QString& username, quint32 poi
// Automatically show the achievements column after first login. If the user has manually hidden it,
// it will not be automatically shown again.
if (!Core::GetBaseBoolSettingValue("GameListTableView", "TriedShowingAchievementsColumn", false))
if (!Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "TriedShowingAchievementsColumn", false))
{
Core::SetBaseBoolSettingValue("GameListTableView", "TriedShowingAchievementsColumn", true);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, "TriedShowingAchievementsColumn", true);
m_game_list_widget->getListView()->setAndSaveColumnHidden(GameListModel::Column_Achievements, false);
}
}
+5 -3
View File
@@ -63,11 +63,13 @@ SettingsWindow::SettingsWindow(const GameList::Entry* entry, std::unique_ptr<INI
if (const QIcon icon = g_main_window->getIconForGame(QString::fromStdString(entry->path)); !icon.isNull())
setWindowIcon(icon);
setGameTitle(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles()));
const bool show_localized_titles = Core::GetBaseBoolSettingValue(
GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_LOCALIZED_TITLES, GameList::DEFAULT_LOCALIZED_TITLES);
setGameTitle(entry->GetDisplayTitle(show_localized_titles));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
addWidget(m_game_summary = new GameSummaryWidget(entry, this, m_ui.settingsContainer), tr("Summary"),
u":/icons/monochrome/svg/file-list-line.svg"_s,
addWidget(m_game_summary = new GameSummaryWidget(entry, show_localized_titles, this, m_ui.settingsContainer),
tr("Summary"), u":/icons/monochrome/svg/file-list-line.svg"_s,
tr("<strong>Summary</strong><hr>This page shows information about the selected game, and allows you to "
"validate your disc was dumped correctly."));
addPages();
+5 -3
View File
@@ -695,7 +695,8 @@ void SetupWizardDialog::onAchievementsViewProfilePressed()
void SetupWizardDialog::setupGameListViewPage()
{
const bool use_grid = Core::GetBaseBoolSettingValue("UI", "GameListGridView", false);
const bool use_grid = Core::GetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_GRID_VIEW,
GameList::DEFAULT_GRID_VIEW);
m_ui.listView->setChecked(!use_grid);
m_ui.gridView->setChecked(use_grid);
@@ -717,8 +718,9 @@ void SetupWizardDialog::onGridViewChanged(bool checked)
return;
// NOTE: No settings apply here, we explicitly change the layout.
Core::SetBaseBoolSettingValue("UI", "GameListGridView", setting_value);
Core::SetBaseUIntSettingValue("Main", "DefaultFullscreenUIGameView", setting_value ? 0 : 1);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_GRID_VIEW, setting_value);
Core::SetBaseBoolSettingValue(GameList::UI_SETTING_SECTION, GameList::SETTING_KEY_FULLSCREENUI_GRID_VIEW,
setting_value);
Host::CommitBaseSettingChanges();
g_main_window->getGameListWidget()->reloadViewModeFromSettings();
}