GameDatabase: Add sort title, localized title, and save title fields

This commit is contained in:
Stenzek
2025-08-30 13:42:55 +10:00
parent 1aa92c7667
commit a8b4bb3fce
10 changed files with 166 additions and 89 deletions

View File

@@ -1994,7 +1994,8 @@ bool Cheats::ImportOldChtFile(const std::string_view serial)
if (!dbentry || dbentry->title.empty())
return false;
const std::string old_path = fmt::format("{}" FS_OSPATH_SEPARATOR_STR "{}.cht", EmuFolders::Cheats, dbentry->title);
const std::string old_path =
fmt::format("{}" FS_OSPATH_SEPARATOR_STR "{}.cht", EmuFolders::Cheats, dbentry->GetSaveTitle());
if (!FileSystem::FileExists(old_path.c_str()))
return false;

View File

@@ -7873,7 +7873,7 @@ void FullscreenUI::PopulateGameListEntryList()
}
// fallback to title when all else is equal
const int res = StringUtil::Strcasecmp(lhs->title.c_str(), rhs->title.c_str());
const int res = StringUtil::CompareNoCase(lhs->GetSortTitle(), rhs->GetSortTitle());
return reverse ? (res > 0) : (res < 0);
});
}
@@ -8026,7 +8026,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
summary.format("{} | {} | {} MB", entry->serial, Path::GetFileName(entry->path), to_mb(entry->file_size));
}
const ImGuiFullscreen::MenuButtonBounds mbb(entry->title, {}, summary, row_left_margin);
const ImGuiFullscreen::MenuButtonBounds mbb(entry->GetDisplayTitle(), {}, summary, row_left_margin);
bool visible, hovered;
bool pressed = MenuButtonFrame(entry->path, true, mbb.frame_bb, &visible, &hovered);
@@ -8042,8 +8042,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
ImGui::GetWindowDrawList()->AddImage(cover_texture, image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f),
ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
RenderShadowedTextClipped(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight, mbb.title_bb.Min,
mbb.title_bb.Max, text_color, entry->title, &mbb.title_size, ImVec2(0.0f, 0.0f),
mbb.title_size.x, &mbb.title_bb);
mbb.title_bb.Max, text_color, entry->GetDisplayTitle(), &mbb.title_size,
ImVec2(0.0f, 0.0f), mbb.title_size.x, &mbb.title_bb);
if (!summary.empty())
{
@@ -8145,12 +8145,13 @@ 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();
// title
ImGui::PushFont(UIStyle.Font, UIStyle.LargeFontSize, UIStyle.BoldFontWeight);
text_width = ImGui::CalcTextSize(selected_entry->title.c_str(), nullptr, false, work_width).x;
text_width = ImGui::CalcTextSize(IMSTR_START_END(title), false, work_width).x;
ImGui::SetCursorPosX((work_width - text_width) / 2.0f);
ImGui::TextWrapped("%s", selected_entry->title.c_str());
ImGui::TextWrapped("%.*s", static_cast<int>(title.size()), title.data());
ImGui::PopFont();
ImGui::PushFont(UIStyle.Font, UIStyle.MediumFontSize, UIStyle.BoldFontWeight);
@@ -8388,8 +8389,9 @@ 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_state.game_list_sorted_entries[row_entry_index];
const std::string_view row_title = row_entry->GetDisplayTitle();
const ImVec2 this_title_size = UIStyle.Font->CalcTextSizeA(title_font_size, title_font_weight, image_width,
image_width, IMSTR_START_END(row_entry->title));
image_width, IMSTR_START_END(row_title));
row_item_height = std::max(row_item_height, this_title_size.y);
}
@@ -8399,8 +8401,9 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
ImVec2 title_size;
if (s_state.game_grid_show_titles)
{
const std::string_view title = entry->GetDisplayTitle();
title_size = UIStyle.Font->CalcTextSizeA(title_font_size, title_font_weight, image_width, image_width,
IMSTR_START_END(entry->title));
IMSTR_START_END(title));
}
const ImGuiID id = window->GetID(entry->path.c_str(), entry->path.c_str() + entry->path.length());
@@ -8448,9 +8451,9 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
if (draw_title)
{
const ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max);
ImGuiFullscreen::RenderMultiLineShadowedTextClipped(dl, UIStyle.Font, title_font_size, title_font_weight,
title_bb.Min, title_bb.Max, text_color, entry->title,
LAYOUT_CENTER_ALIGN_TEXT, image_width, &title_bb);
ImGuiFullscreen::RenderMultiLineShadowedTextClipped(
dl, UIStyle.Font, title_font_size, title_font_weight, title_bb.Min, title_bb.Max, text_color,
entry->GetDisplayTitle(), LAYOUT_CENTER_ALIGN_TEXT, image_width, &title_bb);
}
if (pressed)
@@ -8517,7 +8520,7 @@ void FullscreenUI::HandleGameListOptions(const GameList::Entry* entry)
};
OpenChoiceDialog(
entry->title.c_str(), false, std::move(options),
entry->GetDisplayTitle(), false, std::move(options),
[entry_path = entry->path, entry_serial = entry->serial](s32 index, const std::string& title,
bool checked) mutable {
switch (index)

View File

@@ -40,7 +40,7 @@ namespace GameDatabase {
enum : u32
{
GAME_DATABASE_CACHE_SIGNATURE = 0x45434C48,
GAME_DATABASE_CACHE_VERSION = 28,
GAME_DATABASE_CACHE_VERSION = 29,
};
static const Entry* GetEntryForId(std::string_view code);
@@ -360,6 +360,21 @@ SmallString GameDatabase::Entry::GetLanguagesString() const
return ret;
}
std::string_view GameDatabase::Entry::GetDisplayTitle() const
{
return !localized_title.empty() ? localized_title : title;
}
std::string_view GameDatabase::Entry::GetSortTitle() const
{
return !sort_title.empty() ? sort_title : title;
}
std::string_view GameDatabase::Entry::GetSaveTitle() const
{
return !save_title.empty() ? save_title : title;
}
void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_messages) const
{
if (display_active_start_offset.has_value())
@@ -917,8 +932,14 @@ static inline void AppendEnumSetting(SmallStringBase& str, bool& heading, std::s
std::string GameDatabase::Entry::GenerateCompatibilityReport() const
{
LargeString ret;
ret.append_format("**{}:** {}\n\n", TRANSLATE_SV("GameDatabase", "Title"), title);
ret.append_format("**{}:** {}\n\n", TRANSLATE_SV("GameDatabase", "Serial"), serial);
ret.append_format("**{}:** {}\n\n", TRANSLATE_SV("GameDatabase", "Title"), title);
if (!sort_title.empty())
ret.append_format("**{}:** {}\n\n", TRANSLATE_SV("GameDatabase", "Sort Title"), title);
if (!localized_title.empty())
ret.append_format("**{}:** {}\n\n", TRANSLATE_SV("GameDatabase", "Localized Title"), title);
if (!save_title.empty())
ret.append_format("**{}:** {}\n\n", TRANSLATE_SV("GameDatabase", "Save Title"), title);
if (languages.any())
ret.append_format("**{}:** {}\n\n", TRANSLATE_SV("GameDatabase", "Languages"), GetLanguagesString());
@@ -1052,8 +1073,9 @@ bool GameDatabase::LoadFromCache()
u32 num_disc_set_serials;
if (!reader.ReadSizePrefixedString(&entry.serial) || !reader.ReadSizePrefixedString(&entry.title) ||
!reader.ReadSizePrefixedString(&entry.genre) || !reader.ReadSizePrefixedString(&entry.developer) ||
!reader.ReadSizePrefixedString(&entry.publisher) ||
!reader.ReadSizePrefixedString(&entry.sort_title) || !reader.ReadSizePrefixedString(&entry.localized_title) ||
!reader.ReadSizePrefixedString(&entry.save_title) || !reader.ReadSizePrefixedString(&entry.genre) ||
!reader.ReadSizePrefixedString(&entry.developer) || !reader.ReadSizePrefixedString(&entry.publisher) ||
!reader.ReadSizePrefixedString(&entry.compatibility_version_tested) ||
!reader.ReadSizePrefixedString(&entry.compatibility_comments) || !reader.ReadU64(&entry.release_date) ||
!reader.ReadU8(&entry.min_players) || !reader.ReadU8(&entry.max_players) || !reader.ReadU8(&entry.min_blocks) ||
@@ -1145,6 +1167,9 @@ bool GameDatabase::SaveToCache()
{
writer.WriteSizePrefixedString(entry.serial);
writer.WriteSizePrefixedString(entry.title);
writer.WriteSizePrefixedString(entry.sort_title);
writer.WriteSizePrefixedString(entry.localized_title);
writer.WriteSizePrefixedString(entry.save_title);
writer.WriteSizePrefixedString(entry.genre);
writer.WriteSizePrefixedString(entry.developer);
writer.WriteSizePrefixedString(entry.publisher);
@@ -1282,6 +1307,9 @@ bool GameDatabase::LoadGameDBYaml()
bool GameDatabase::ParseYamlEntry(Entry* entry, const ryml::ConstNodeRef& value)
{
GetStringFromObject(value, "name", &entry->title);
GetStringFromObject(value, "sortName", &entry->sort_title);
GetStringFromObject(value, "localizedName", &entry->localized_title);
GetStringFromObject(value, "saveName", &entry->save_title);
entry->supported_controllers = static_cast<u16>(~0u);

View File

@@ -100,53 +100,75 @@ struct Entry
{
static constexpr u16 SUPPORTS_MULTITAP_BIT = (1u << static_cast<u8>(ControllerType::Count));
std::string_view serial;
std::string_view title;
std::string_view genre;
std::string_view developer;
std::string_view publisher;
std::string_view compatibility_version_tested;
std::string_view compatibility_comments;
u64 release_date; ///< Number of seconds since Epoch.
u8 min_players;
u8 max_players;
u8 min_blocks;
u8 max_blocks;
u16 supported_controllers;
CompatibilityRating compatibility;
std::string_view serial; ///< Official serial of the game, e.g. "SLUS-00001".
std::string_view title; ///< Official title of the game.
std::string_view sort_title; ///< Title used for sorting in game lists.
std::string_view localized_title; ///< Title in the native language, if available.
std::string_view save_title; ///< Title used for per-game memory cards.
std::string_view genre; ///< Genre of the game.
std::string_view developer; ///< Developer of the game.
std::string_view publisher; ///< Publisher of the game.
std::string_view compatibility_version_tested; ///< Version of the application the game was tested with.
std::string_view compatibility_comments; ///< Comments about the game's compatibility.
u64 release_date; ///< Number of seconds since Epoch.
u8 min_players; ///< Minimum number of players supported.
u8 max_players; ///< Maximum number of players supported.
u8 min_blocks; ///< Minimum number of blocks the game uses.
u8 max_blocks; ///< Maximum number of blocks the game uses.
u16 supported_controllers; ///< Bitfield of supported controllers.
CompatibilityRating compatibility; ///< Compatibility rating of the game.
std::bitset<static_cast<size_t>(Trait::MaxCount)> traits{};
std::bitset<static_cast<size_t>(Language::MaxCount)> languages{};
std::optional<s16> display_active_start_offset;
std::optional<s16> display_active_end_offset;
std::optional<s8> display_line_start_offset;
std::optional<s8> display_line_end_offset;
std::optional<DisplayCropMode> display_crop_mode;
std::optional<DisplayDeinterlacingMode> display_deinterlacing_mode;
std::optional<GPULineDetectMode> gpu_line_detect_mode;
std::optional<u8> cpu_overclock;
std::optional<u32> dma_max_slice_ticks;
std::optional<u32> dma_halt_ticks;
std::optional<u32> cdrom_max_seek_speedup_cycles;
std::optional<u32> cdrom_max_read_speedup_cycles;
std::optional<u32> gpu_fifo_size;
std::optional<u32> gpu_max_run_ahead;
std::optional<float> gpu_pgxp_tolerance;
std::optional<float> gpu_pgxp_depth_threshold;
std::optional<bool> gpu_pgxp_preserve_proj_fp;
std::bitset<static_cast<size_t>(Trait::MaxCount)> traits{}; ///< Traits for the game.
std::bitset<static_cast<size_t>(Language::MaxCount)> languages{}; ///< Languages supported by the game.
std::optional<s16> display_active_start_offset; ///< Display active start offset override.
std::optional<s16> display_active_end_offset; ///< Display active end offset override.
std::optional<s8> display_line_start_offset; ///< Display line start offset override.
std::optional<s8> display_line_end_offset; ///< Display line end offset override.
std::optional<DisplayCropMode> display_crop_mode; ///< Display crop mode override.
std::optional<DisplayDeinterlacingMode> display_deinterlacing_mode; ///< Display deinterlacing mode override.
std::optional<GPULineDetectMode> gpu_line_detect_mode; ///< GPU line detect mode override.
std::optional<u8> cpu_overclock; ///< CPU overclock percentage override.
std::optional<u32> dma_max_slice_ticks; ///< DMA max slice ticks override.
std::optional<u32> dma_halt_ticks; ///< DMA halt ticks override.
std::optional<u32> cdrom_max_seek_speedup_cycles; ///< CD-ROM max seek speedup cycles override.
std::optional<u32> cdrom_max_read_speedup_cycles; ///< CD-ROM max read speedup cycles override.
std::optional<u32> gpu_fifo_size; ///< GPU FIFO size override.
std::optional<u32> gpu_max_run_ahead; ///< GPU max runahead override.
std::optional<float> gpu_pgxp_tolerance; ///< GPU PGXP tolerance override.
std::optional<float> gpu_pgxp_depth_threshold; ///< GPU PGXP depth threshold override.
std::optional<bool> gpu_pgxp_preserve_proj_fp; ///< GPU PGXP preserve projection precision override.
std::string_view disc_set_name;
std::vector<std::string_view> disc_set_serials;
std::string_view disc_set_name; ///< Name of the disc set, if applicable.
std::vector<std::string_view> disc_set_serials; ///< Serials of all discs in the set.
/// Checks if a trait is present.
ALWAYS_INLINE bool HasTrait(Trait trait) const { return traits[static_cast<int>(trait)]; }
/// Checks if a language is present.
ALWAYS_INLINE bool HasLanguage(Language language) const { return languages.test(static_cast<size_t>(language)); }
/// Checks if any language is present.
ALWAYS_INLINE bool HasAnyLanguage() const { return languages.any(); }
/// Returns the flag for the game's language if it only has one, and it is not English. Otherwise the region.
std::string_view GetLanguageFlagName(DiscRegion region) const;
/// Returns a comma-separated list of language names.
SmallString GetLanguagesString() const;
/// Returns the title that should be displayed for this game.
std::string_view GetDisplayTitle() const;
/// Returns the sort name if present, otherwise the title.
std::string_view GetSortTitle() const;
/// Returns the name to use when creating memory cards for this game.
std::string_view GetSaveTitle() const;
/// Applies any settings overrides to the given settings object.
void ApplySettings(Settings& settings, bool display_osd_messages) const;
/// Generates a compatibility report in markdown format.
std::string GenerateCompatibilityReport() const;
};

View File

@@ -319,7 +319,7 @@ bool GameList::GetDiscListEntry(const std::string& path, Entry* entry)
{
// pull from database
entry->serial = dentry->serial;
entry->title = dentry->title;
entry->title = dentry->GetDisplayTitle();
entry->dbentry = dentry;
if (!cdi->HasSubImages())
@@ -1255,6 +1255,24 @@ std::string GameList::GetNewCoverImagePathForEntry(const Entry* entry, const cha
return Path::Combine(EmuFolders::Covers, Path::SanitizeFileName(name));
}
std::string_view GameList::Entry::GetDisplayTitle() const
{
// if custom title is present, use that for display too
return has_custom_title ? title : (dbentry ? dbentry->GetDisplayTitle() : title);
}
std::string_view GameList::Entry::GetSortTitle() const
{
// if custom title is present, use that for sorting too
return has_custom_title ? title : (dbentry ? dbentry->GetSortTitle() : title);
}
std::string_view GameList::Entry::GetSaveTitle() const
{
// if custom title is present, use that for save folder too
return has_custom_title ? title : (dbentry ? dbentry->GetSaveTitle() : title);
}
std::string_view GameList::Entry::GetLanguageIcon() const
{
std::string_view ret;

View File

@@ -60,6 +60,12 @@ struct Entry
u16 unlocked_achievements = 0;
u16 unlocked_achievements_hc = 0;
std::string_view GetDisplayTitle() const;
std::string_view GetSortTitle() const;
std::string_view GetSaveTitle() const;
std::string_view GetLanguageIcon() const;
TinyString GetLanguageIconName() const;

View File

@@ -3445,8 +3445,7 @@ u32 System::CompressAndWriteStateData(std::FILE* fp, std::span<const u8> src, Sa
{
ctype = CompressHelpers::CompressType::XZ;
*header_type = static_cast<u32>(SAVE_STATE_HEADER::CompressionType::XZ);
clevel =
((method == SaveStateCompressionMode::XZLow) ? 1 : ((method == SaveStateCompressionMode::XZHigh) ? 9 : 5));
clevel = ((method == SaveStateCompressionMode::XZLow) ? 1 : ((method == SaveStateCompressionMode::XZHigh) ? 9 : 5));
}
else
{
@@ -3808,11 +3807,12 @@ std::unique_ptr<MemoryCard> System::GetMemoryCardForSlot(u32 slot, MemoryCardTyp
}
else
{
const std::string_view game_title =
s_state.running_game_custom_title ? s_state.running_game_title : s_state.running_game_entry->GetSaveTitle();
std::string card_path;
// Playlist - use title if different.
if (HasMediaSubImages() && s_state.running_game_entry &&
s_state.running_game_title != s_state.running_game_entry->title)
if (HasMediaSubImages() && s_state.running_game_entry && s_state.running_game_title != game_title)
{
card_path = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(s_state.running_game_title), slot);
}
@@ -3824,11 +3824,7 @@ std::unique_ptr<MemoryCard> System::GetMemoryCardForSlot(u32 slot, MemoryCardTyp
}
// But prefer a disc-specific card if one already exists.
std::string disc_card_path = g_settings.GetGameMemoryCardPath(
Path::SanitizeFileName((s_state.running_game_entry && !s_state.running_game_custom_title) ?
s_state.running_game_entry->title :
s_state.running_game_title),
slot);
std::string disc_card_path = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(game_title), slot);
if (disc_card_path != card_path)
{
if (card_path.empty() || !g_settings.memory_card_use_playlist_title ||
@@ -4157,7 +4153,7 @@ 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->title;
s_state.running_game_title = s_state.running_game_entry->GetDisplayTitle();
else if (s_state.running_game_title.empty())
s_state.running_game_title = s_state.running_game_serial;
}
@@ -4176,7 +4172,7 @@ void System::UpdateRunningGame(const std::string& path, CDImage* image, bool boo
{
s_state.running_game_serial = s_state.running_game_entry->serial;
if (s_state.running_game_title.empty())
s_state.running_game_title = s_state.running_game_entry->title;
s_state.running_game_title = s_state.running_game_entry->GetDisplayTitle();
}
else
{
@@ -5775,7 +5771,7 @@ std::string System::GetGameMemoryCardPath(std::string_view serial, std::string_v
const GameDatabase::Entry* entry = GameDatabase::GetEntryForSerial(serial);
if (entry)
{
ret = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->title), slot);
ret = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->GetSaveTitle()), slot);
// Use disc set name if there isn't a per-disc card present.
const bool global_use_playlist_title = Host::GetBaseBoolSettingValue(section, "UsePlaylistTitle", true);
@@ -6193,7 +6189,7 @@ void System::UpdateRichPresence(bool update_session_time)
{
// Use disc set name if it's not a custom title.
if (s_state.running_game_entry && !s_state.running_game_entry->disc_set_name.empty() &&
s_state.running_game_title == s_state.running_game_entry->title)
s_state.running_game_title == s_state.running_game_entry->GetDisplayTitle())
{
game_details = s_state.running_game_entry->disc_set_name;
}

View File

@@ -529,7 +529,7 @@ QVariant GameListModel::data(const QModelIndex& index, int role, const GameList:
return QtUtils::StringViewToQString(ge->serial);
case Column_Title:
return QtUtils::StringViewToQString(ge->title);
return QtUtils::StringViewToQString(ge->GetDisplayTitle());
case Column_FileTitle:
return QtUtils::StringViewToQString(Path::GetFileTitle(ge->path));
@@ -589,7 +589,7 @@ QVariant GameListModel::data(const QModelIndex& index, int role, const GameList:
case Column_Cover:
{
if (m_show_titles_for_covers)
return QString::fromStdString(ge->title);
return QtUtils::StringViewToQString(ge->GetDisplayTitle());
else
return {};
}
@@ -665,7 +665,7 @@ QVariant GameListModel::data(const QModelIndex& index, int role, const GameList:
return QtUtils::StringViewToQString(ge->serial);
case Column_Title:
return QtUtils::StringViewToQString(ge->title);
return QtUtils::StringViewToQString(ge->GetDisplayTitle());
case Column_FileTitle:
return QtUtils::StringViewToQString(Path::GetFileTitle(ge->path));
@@ -761,7 +761,7 @@ void GameListModel::refresh()
bool GameListModel::titlesLessThan(const GameList::Entry* left, const GameList::Entry* right) const
{
return (StringUtil::Strcasecmp(left->title.c_str(), right->title.c_str()) < 0);
return (StringUtil::CompareNoCase(left->GetSortTitle(), right->GetSortTitle()) < 0);
}
bool GameListModel::lessThan(const QModelIndex& left_index, const QModelIndex& right_index, int column) const
@@ -1070,9 +1070,9 @@ public:
if (!m_filter_name.empty())
{
if (!((!entry->IsDiscSet() && !entry->path.empty() && StringUtil::ContainsNoCase(entry->path, m_filter_name)) ||
(!entry->serial.empty() && StringUtil::ContainsNoCase(entry->serial, m_filter_name)) ||
(!entry->title.empty() && StringUtil::ContainsNoCase(entry->title, m_filter_name))))
if (!((!entry->IsDiscSet() && StringUtil::ContainsNoCase(entry->path, m_filter_name)) ||
StringUtil::ContainsNoCase(entry->serial, m_filter_name) ||
StringUtil::ContainsNoCase(entry->GetDisplayTitle(), m_filter_name)))
{
return false;
}
@@ -1445,7 +1445,10 @@ void GameListWidget::onListViewItemActivated(const QModelIndex& index)
const auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryByIndex(static_cast<u32>(source_index.row()));
if (entry)
SettingsWindow::openGamePropertiesDialog(entry->path, entry->title, entry->serial, entry->hash, entry->region);
{
SettingsWindow::openGamePropertiesDialog(entry->path, std::string(entry->GetDisplayTitle()), entry->serial,
entry->hash, entry->region);
}
}
else
{
@@ -1678,9 +1681,8 @@ void GameListListView::setFixedColumnWidth(const QFontMetrics& fm, int column, i
const int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, nullptr, this);
const int header_width = fm.size(0, m_model->getColumnDisplayName(column)).width() +
style()->pixelMetric(QStyle::PM_HeaderMarkSize, nullptr, this) + // sort indicator
margin; // space between text and sort indicator
const int width = std::max(header_width, str_width) +
2 * margin; // left and right margins
margin; // space between text and sort indicator
const int width = std::max(header_width, str_width) + 2 * margin; // left and right margins
setFixedColumnWidth(column, width);
}
@@ -1703,11 +1705,12 @@ void GameListListView::setFixedColumnWidths()
// And this is a monstrosity.
setFixedColumnWidth(
fm, GameListModel::Column_LastPlayed,
std::max(width_for(qApp->translate("GameList", "Today")),
std::max(width_for(qApp->translate("GameList", "Yesterday")),
std::max(width_for(qApp->translate("GameList", "Never")),
width_for(QtHost::FormatNumber(Host::NumberFormatType::ShortDate,
static_cast<s64>(QDateTime::currentSecsSinceEpoch())))))));
std::max(
width_for(qApp->translate("GameList", "Today")),
std::max(width_for(qApp->translate("GameList", "Yesterday")),
std::max(width_for(qApp->translate("GameList", "Never")),
width_for(QtHost::FormatNumber(Host::NumberFormatType::ShortDate,
static_cast<s64>(QDateTime::currentSecsSinceEpoch())))))));
// Assume 8 is the widest digit.
int size_width = width_for(QStringLiteral("%1 MB").arg(8888.88, 0, 'f', 2));

View File

@@ -126,7 +126,7 @@ void GameSummaryWidget::populateUi(const std::string& path, const std::string& s
if (entry)
{
m_ui.title->setText(QtUtils::StringViewToQString(entry->title));
m_ui.title->setText(QtUtils::StringViewToQString(entry->GetDisplayTitle()));
m_ui.compatibility->setCurrentIndex(static_cast<int>(entry->compatibility));
m_ui.genre->setText(entry->genre.empty() ? tr("Unknown") : QtUtils::StringViewToQString(entry->genre));
if (!entry->developer.empty() && !entry->publisher.empty() && entry->developer != entry->publisher)
@@ -268,7 +268,7 @@ void GameSummaryWidget::populateCustomAttributes()
{
QSignalBlocker sb(m_ui.title);
m_ui.title->setText(QString::fromStdString(entry->title));
m_ui.title->setText(QtUtils::StringViewToQString(entry->GetDisplayTitle()));
m_ui.restoreTitle->setEnabled(entry->has_custom_title);
}

View File

@@ -1565,8 +1565,8 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
if (!entry)
return;
SettingsWindow::openGamePropertiesDialog(entry->path, entry->title, entry->serial, entry->hash,
entry->region);
SettingsWindow::openGamePropertiesDialog(entry->path, std::string(entry->GetDisplayTitle()), entry->serial,
entry->hash, entry->region);
});
connect(menu.addAction(tr("Open Containing Directory...")), &QAction::triggered, [this, qpath]() {
@@ -1644,8 +1644,8 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
const GameList::Entry* first_disc = GameList::GetFirstDiscSetMember(disc_set_name.toStdString());
if (first_disc)
{
SettingsWindow::openGamePropertiesDialog(first_disc->path, first_disc->title, first_disc->serial,
first_disc->hash, first_disc->region);
SettingsWindow::openGamePropertiesDialog(first_disc->path, std::string(first_disc->GetDisplayTitle()),
first_disc->serial, first_disc->hash, first_disc->region);
}
});
@@ -1743,7 +1743,7 @@ void MainWindow::clearGameListEntryPlayTime(const GameList::Entry* entry)
if (QMessageBox::question(
this, tr("Confirm Reset"),
tr("Are you sure you want to reset the play time for '%1'?\n\nThis action cannot be undone.")
.arg(QString::fromStdString(entry->title))) != QMessageBox::Yes)
.arg(QtUtils::StringViewToQString(entry->GetDisplayTitle()))) != QMessageBox::Yes)
{
return;
}