Qt: Pass game list entry to settings window

Simplfies everything, makes restoring custom properties more reliable.
pull/3563/head
Stenzek 2 months ago
parent d367e7e4e0
commit 022d9f3083
No known key found for this signature in database

@ -1429,6 +1429,14 @@ std::string System::GetGameSettingsPath(std::string_view game_serial, bool ignor
return Path::Combine(EmuFolders::GameSettings, fmt::format("{}.ini", Path::SanitizeFileName(serial_for_path)));
}
bool System::ShouldUseSeparateDiscSettingsForSerial(std::string_view game_serial)
{
const std::string path = GetGameSettingsPath(game_serial, false);
INISettingsInterface ini(path);
ini.Load();
return ini.GetBoolValue("Main", "UseSeparateConfigForDiscSet", false);
}
std::unique_ptr<INISettingsInterface> System::GetGameSettingsInterface(const GameDatabase::Entry* dbentry,
std::string_view serial, bool create, bool quiet)
{

@ -157,6 +157,9 @@ DiscRegion GetRegionForPsf(const char* path);
/// Returns the path for the game settings ini file for the specified serial.
std::string GetGameSettingsPath(std::string_view game_serial, bool ignore_disc_set);
/// Returns true if separate disc settings should be used for the specified serial.
bool ShouldUseSeparateDiscSettingsForSerial(std::string_view game_serial);
/// Returns the loaded interface for the game settings ini file for the specified serial. If create is true, an empty
/// ini reader will be returned if the file does not exist. If quit is true, no log messages will be emitted.
std::unique_ptr<INISettingsInterface> GetGameSettingsInterface(const GameDatabase::Entry* dbentry,

@ -293,7 +293,6 @@ void GameListModel::setDevicePixelRatio(qreal dpr)
if (m_device_pixel_ratio == dpr)
return;
WARNING_LOG("NEW DPR {}", dpr);
m_device_pixel_ratio = dpr;
m_placeholder_image.setDevicePixelRatio(dpr);
m_loading_pixmap.setDevicePixelRatio(dpr);
@ -1545,11 +1544,7 @@ 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,
std::string(entry->GetDisplayTitle(m_model->getShowLocalizedTitles())),
entry->serial, entry->hash, entry->region);
}
SettingsWindow::openGamePropertiesDialog(entry);
}
else
{

@ -27,8 +27,7 @@
#include "moc_gamesummarywidget.cpp"
GameSummaryWidget::GameSummaryWidget(const std::string& path, const std::string& serial, DiscRegion region,
const GameDatabase::Entry* entry, SettingsWindow* dialog, QWidget* parent)
GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, SettingsWindow* dialog, QWidget* parent)
: m_dialog(dialog)
{
m_ui.setupUi(this);
@ -56,7 +55,7 @@ GameSummaryWidget::GameSummaryWidget(const std::string& path, const std::string&
// I hate this so much.
const std::string_view default_language =
entry ? entry->GetLanguageFlagName(region) : Settings::GetDiscRegionName(region);
entry->dbentry ? entry->dbentry->GetLanguageFlagName(entry->region) : Settings::GetDiscRegionName(entry->region);
m_ui.customLanguage->addItem(QtUtils::GetIconForLanguage(default_language), tr("Show Default Flag"));
for (u32 i = 0; i < static_cast<u32>(GameDatabase::Language::MaxCount); i++)
{
@ -64,7 +63,7 @@ GameSummaryWidget::GameSummaryWidget(const std::string& path, const std::string&
m_ui.customLanguage->addItem(QtUtils::GetIconForLanguage(language_name), QString::fromUtf8(language_name));
}
populateUi(path, serial, region, entry);
populateUi(entry);
connect(m_ui.compatibilityComments, &QToolButton::clicked, this, &GameSummaryWidget::onCompatibilityCommentsClicked);
connect(m_ui.inputProfile, &QComboBox::currentIndexChanged, this, &GameSummaryWidget::onInputProfileChanged);
@ -115,69 +114,77 @@ void GameSummaryWidget::reloadGameSettings()
m_ui.editInputProfile->setEnabled(m_ui.inputProfile->currentIndex() >= 1);
}
void GameSummaryWidget::populateUi(const std::string& path, const std::string& serial, DiscRegion region,
const GameDatabase::Entry* entry)
void GameSummaryWidget::populateUi(const GameList::Entry* entry)
{
m_path = path;
m_path = entry->path;
m_ui.path->setText(QString::fromStdString(path));
m_ui.serial->setText(QString::fromStdString(serial));
m_ui.region->setCurrentIndex(static_cast<int>(region));
m_ui.path->setText(QString::fromStdString(entry->path));
m_ui.serial->setText(QString::fromStdString(entry->serial));
m_ui.title->setText(QtUtils::StringViewToQString(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles())));
m_ui.region->setCurrentIndex(static_cast<int>(entry->region));
m_ui.entryType->setCurrentIndex(static_cast<int>(entry->type));
if (entry)
m_ui.restoreTitle->setEnabled(entry->has_custom_title);
m_ui.restoreRegion->setEnabled(entry->has_custom_region);
// can't set languages on disc set entries
m_ui.customLanguage->setCurrentIndex(entry->HasCustomLanguage() ? (static_cast<u32>(entry->custom_language) + 1) : 0);
if (entry->IsDiscSet())
m_ui.customLanguage->setEnabled(false);
if (const GameDatabase::Entry* dbentry = entry->dbentry)
{
m_ui.title->setText(QtUtils::StringViewToQString(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles())));
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)
m_ui.compatibility->setCurrentIndex(static_cast<int>(dbentry->compatibility));
m_ui.genre->setText(dbentry->genre.empty() ? tr("Unknown") : QtUtils::StringViewToQString(dbentry->genre));
if (!dbentry->developer.empty() && !dbentry->publisher.empty() && dbentry->developer != dbentry->publisher)
m_ui.developer->setText(tr("%1 (Published by %2)")
.arg(QtUtils::StringViewToQString(entry->developer))
.arg(QtUtils::StringViewToQString(entry->publisher)));
else if (!entry->developer.empty())
m_ui.developer->setText(QtUtils::StringViewToQString(entry->developer));
else if (!entry->publisher.empty())
m_ui.developer->setText(tr("Published by %1").arg(QtUtils::StringViewToQString(entry->publisher)));
.arg(QtUtils::StringViewToQString(dbentry->developer))
.arg(QtUtils::StringViewToQString(dbentry->publisher)));
else if (!dbentry->developer.empty())
m_ui.developer->setText(QtUtils::StringViewToQString(dbentry->developer));
else if (!dbentry->publisher.empty())
m_ui.developer->setText(tr("Published by %1").arg(QtUtils::StringViewToQString(dbentry->publisher)));
else
m_ui.developer->setText(tr("Unknown"));
QString release_info;
if (entry->release_date != 0)
if (dbentry->release_date != 0)
{
const QString date = QDateTime::fromSecsSinceEpoch(static_cast<qint64>(entry->release_date), QTimeZone::utc())
const QString date = QDateTime::fromSecsSinceEpoch(static_cast<qint64>(dbentry->release_date), QTimeZone::utc())
.toString(QtHost::GetApplicationLocale().dateFormat());
release_info = tr("Released %1").arg(date);
}
if (entry->min_players != 0)
if (dbentry->min_players != 0)
{
if (!release_info.isEmpty())
release_info.append(", ");
if (entry->min_players != entry->max_players)
release_info.append(tr("%1-%2 players").arg(entry->min_players).arg(entry->max_players));
if (dbentry->min_players != dbentry->max_players)
release_info.append(tr("%1-%2 players").arg(dbentry->min_players).arg(dbentry->max_players));
else
release_info.append(tr("%1 players").arg(entry->min_players));
release_info.append(tr("%1 players").arg(dbentry->min_players));
}
if (entry->min_blocks != 0)
if (dbentry->min_blocks != 0)
{
if (!release_info.isEmpty())
release_info.append(", ");
if (entry->min_blocks != entry->max_blocks)
release_info.append(tr("%1-%2 memory card blocks").arg(entry->min_blocks).arg(entry->max_blocks));
if (dbentry->min_blocks != dbentry->max_blocks)
release_info.append(tr("%1-%2 memory card blocks").arg(dbentry->min_blocks).arg(dbentry->max_blocks));
else
release_info.append(tr("%1 memory card blocks").arg(entry->min_blocks));
release_info.append(tr("%1 memory card blocks").arg(dbentry->min_blocks));
}
if (!release_info.isEmpty())
m_ui.releaseInfo->setText(release_info);
else
m_ui.releaseInfo->setText(tr("Unknown"));
m_ui.languages->setText(QtUtils::StringViewToQString(entry->GetLanguagesString()));
m_ui.languages->setText(QtUtils::StringViewToQString(dbentry->GetLanguagesString()));
QString controllers;
if (entry->supported_controllers != 0 && entry->supported_controllers != static_cast<u16>(-1))
if (dbentry->supported_controllers != 0 && dbentry->supported_controllers != static_cast<u16>(-1))
{
for (u32 i = 0; i < static_cast<u32>(ControllerType::Count); i++)
{
if ((entry->supported_controllers & static_cast<u16>(1u << i)) != 0)
if ((dbentry->supported_controllers & static_cast<u16>(1u << i)) != 0)
{
if (!controllers.isEmpty())
controllers.append(", ");
@ -189,27 +196,19 @@ void GameSummaryWidget::populateUi(const std::string& path, const std::string& s
controllers = tr("Unknown");
m_ui.controllers->setText(controllers);
m_compatibility_comments = QString::fromStdString(entry->GenerateCompatibilityReport());
m_compatibility_comments = QString::fromStdString(dbentry->GenerateCompatibilityReport());
}
else
{
m_ui.title->setText(tr("Unknown"));
m_ui.genre->setText(tr("Unknown"));
m_ui.developer->setText(tr("Unknown"));
m_ui.releaseInfo->setText(tr("Unknown"));
m_ui.controllers->setText(tr("Unknown"));
}
if (entry->dbentry && entry->dbentry->disc_set)
{
auto lock = GameList::GetLock();
const GameList::Entry* gentry = GameList::GetEntryForPath(path);
if (gentry)
m_ui.entryType->setCurrentIndex(static_cast<int>(gentry->type));
}
if (entry && entry->disc_set)
{
if (entry->IsFirstDiscInSet())
if (entry->dbentry->IsFirstDiscInSet())
{
m_ui.separateDiscSettings->setCheckState(
m_dialog->getBoolValue("Main", "UseSeparateConfigForDiscSet", std::nullopt).value_or(false) ? Qt::Checked :
@ -238,9 +237,7 @@ void GameSummaryWidget::populateUi(const std::string& path, const std::string& s
m_ui.inputProfile->addItem(QString::fromStdString(name));
reloadGameSettings();
populateCustomAttributes();
populateTracksInfo();
updateWindowTitle();
}
void GameSummaryWidget::onSeparateDiscSettingsChanged(Qt::CheckState state)
@ -251,57 +248,52 @@ void GameSummaryWidget::onSeparateDiscSettingsChanged(Qt::CheckState state)
m_dialog->removeSettingValue("Main", "UseSeparateConfigForDiscSet");
}
void GameSummaryWidget::updateWindowTitle()
void GameSummaryWidget::setCustomTitle(const std::string& text)
{
m_dialog->setGameTitle(m_ui.title->text().toStdString());
}
GameList::SaveCustomTitleForPath(m_path, text);
void GameSummaryWidget::populateCustomAttributes()
{
auto lock = GameList::GetLock();
{
const auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(m_path);
if (!entry || entry->IsDiscSet())
if (entry)
{
m_ui.customLanguage->setEnabled(false);
return;
}
const std::string_view title = entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles());
m_dialog->setGameTitle(title);
{
QSignalBlocker sb(m_ui.title);
m_ui.title->setText(QtUtils::StringViewToQString(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles())));
const QSignalBlocker sb(m_ui.title);
m_ui.title->setText(QtUtils::StringViewToQString(title));
}
m_ui.restoreTitle->setEnabled(entry->has_custom_title);
{
QSignalBlocker sb(m_ui.region);
m_ui.region->setCurrentIndex(static_cast<int>(entry->region));
m_ui.restoreTitle->setEnabled(entry->has_custom_title);
}
m_ui.restoreRegion->setEnabled(entry->has_custom_region);
{
QSignalBlocker sb(m_ui.customLanguage);
m_ui.customLanguage->setCurrentIndex(entry->HasCustomLanguage() ? (static_cast<u32>(entry->custom_language) + 1) :
0);
}
}
void GameSummaryWidget::setCustomTitle(const std::string& text)
{
m_ui.restoreTitle->setEnabled(!text.empty());
GameList::SaveCustomTitleForPath(m_path, text);
populateCustomAttributes();
updateWindowTitle();
g_main_window->refreshGameListModel();
}
void GameSummaryWidget::setCustomRegion(int region)
{
m_ui.restoreRegion->setEnabled(region >= 0);
GameList::SaveCustomRegionForPath(m_path, (region >= 0) ? std::optional<DiscRegion>(static_cast<DiscRegion>(region)) :
std::optional<DiscRegion>());
populateCustomAttributes();
{
const auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(m_path);
if (entry)
{
const std::string_view title = entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles());
m_dialog->setGameTitle(title);
{
const QSignalBlocker sb(m_ui.region);
m_ui.region->setCurrentIndex(static_cast<int>(entry->region));
}
m_ui.restoreRegion->setEnabled(entry->has_custom_region);
}
}
g_main_window->refreshGameListModel();
}
@ -310,7 +302,7 @@ void GameSummaryWidget::onCustomLanguageChanged(int language)
GameList::SaveCustomLanguageForPath(
m_path, (language > 0) ? std::optional<GameDatabase::Language>(static_cast<GameDatabase::Language>(language - 1)) :
std::optional<GameDatabase::Language>());
populateCustomAttributes();
g_main_window->refreshGameListModel();
}

@ -9,7 +9,7 @@
enum class DiscRegion : u8;
namespace GameDatabase {
namespace GameList {
struct Entry;
}
@ -20,8 +20,7 @@ class GameSummaryWidget : public QWidget
Q_OBJECT
public:
GameSummaryWidget(const std::string& path, const std::string& serial, DiscRegion region,
const GameDatabase::Entry* entry, SettingsWindow* dialog, QWidget* parent);
GameSummaryWidget(const GameList::Entry* entry, SettingsWindow* dialog, QWidget* parent);
~GameSummaryWidget();
void reloadGameSettings();
@ -35,10 +34,7 @@ private Q_SLOTS:
void onComputeHashClicked();
private:
void populateUi(const std::string& path, const std::string& serial, DiscRegion region,
const GameDatabase::Entry* entry);
void populateCustomAttributes();
void updateWindowTitle();
void populateUi(const GameList::Entry* entry);
void setCustomTitle(const std::string& text);
void setCustomRegion(int region);
void setRevisionText(const QString& text);

@ -1567,11 +1567,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
if (!entry || !g_main_window)
return;
SettingsWindow::openGamePropertiesDialog(
entry->path,
std::string(
entry->GetDisplayTitle(g_main_window->m_game_list_widget->getModel()->getShowLocalizedTitles())),
entry->serial, entry->hash, entry->region);
SettingsWindow::openGamePropertiesDialog(entry);
});
connect(menu.addAction(tr("Open Containing Directory...")), &QAction::triggered, [this, qpath]() {
@ -1648,13 +1644,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
auto lock = GameList::GetLock();
const GameList::Entry* first_disc = GameList::GetFirstDiscSetMember(dsentry);
if (first_disc && g_main_window)
{
SettingsWindow::openGamePropertiesDialog(
first_disc->path,
std::string(
first_disc->GetDisplayTitle(g_main_window->m_game_list_widget->getModel()->getShowLocalizedTitles())),
first_disc->serial, first_disc->hash, first_disc->region);
}
SettingsWindow::openGamePropertiesDialog(first_disc);
});
connect(menu.addAction(tr("Set Cover Image...")), &QAction::triggered, [this, qpath]() {
@ -2619,18 +2609,22 @@ void MainWindow::openGamePropertiesForCurrentGame(const char* category /* = null
if (!s_system_valid)
return;
Host::RunOnCPUThread([category]() {
const std::string& path = System::GetGamePath();
const std::string& serial = System::GetGameSerial();
if (path.empty() || serial.empty())
auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(s_current_game_path.toStdString());
if (entry && entry->disc_set_member && !entry->dbentry->IsFirstDiscInSet() &&
!System::ShouldUseSeparateDiscSettingsForSerial(entry->serial))
{
// show for first disc instead
entry = GameList::GetFirstDiscSetMember(entry->dbentry->disc_set);
}
if (!entry)
{
lock.unlock();
QMessageBox::critical(this, tr("Error"), tr("Game properties is only available for scanned games."));
return;
}
Host::RunOnUIThread([title = std::string(System::GetGameTitle()), path = std::string(path),
serial = std::string(serial), hash = System::GetGameHash(), region = System::GetDiscRegion(),
category]() {
SettingsWindow::openGamePropertiesDialog(path, title, std::move(serial), hash, region, category);
});
});
SettingsWindow::openGamePropertiesDialog(entry);
}
ControllerSettingsWindow* MainWindow::getControllerSettingsWindow()

@ -50,17 +50,15 @@ SettingsWindow::SettingsWindow() : QWidget()
connectUi();
}
SettingsWindow::SettingsWindow(const std::string& path, std::string title, std::string serial, GameHash hash,
DiscRegion region, const GameDatabase::Entry* entry,
std::unique_ptr<INISettingsInterface> sif)
: QWidget(), m_sif(std::move(sif)), m_database_entry(entry), m_serial(std::move(serial)), m_hash(hash)
SettingsWindow::SettingsWindow(const GameList::Entry* entry, std::unique_ptr<INISettingsInterface> sif)
: QWidget(), m_sif(std::move(sif)), m_database_entry(entry->dbentry), m_serial(entry->serial), m_hash(entry->hash)
{
m_ui.setupUi(this);
setGameTitle(std::move(title));
setGameTitle(entry->GetDisplayTitle(GameList::ShouldShowLocalizedTitles()));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
addWidget(m_game_summary = new GameSummaryWidget(path, m_serial, region, entry, this, m_ui.settingsContainer),
tr("Summary"), QStringLiteral("file-list-line"),
addWidget(m_game_summary = new GameSummaryWidget(entry, this, m_ui.settingsContainer), tr("Summary"),
QStringLiteral("file-list-line"),
tr("<strong>Summary</strong><hr>This page shows information about the selected game, and allows you to "
"validate your disc was dumped correctly."));
addPages();
@ -647,13 +645,13 @@ void SettingsWindow::saveAndReloadGameSettings()
g_emu_thread->reloadGameSettings(false);
}
void SettingsWindow::setGameTitle(std::string title)
void SettingsWindow::setGameTitle(std::string_view title)
{
m_title = std::move(title);
m_title = title;
const QString window_title =
tr("%1 [%2]")
.arg(QString::fromStdString(m_title))
.arg(QtUtils::StringViewToQString(title))
.arg(QtUtils::StringViewToQString(m_sif ? Path::GetFileName(m_sif->GetPath()) : std::string_view(m_serial)));
setWindowTitle(window_title);
}
@ -664,53 +662,30 @@ bool SettingsWindow::hasGameTrait(GameDatabase::Trait trait)
m_sif->GetBoolValue("Main", "ApplyCompatibilitySettings", true));
}
SettingsWindow* SettingsWindow::openGamePropertiesDialog(const std::string& path, std::string title, std::string serial,
GameHash hash, DiscRegion region,
SettingsWindow* SettingsWindow::openGamePropertiesDialog(const GameList::Entry* entry,
const char* category /* = nullptr */)
{
const GameDatabase::Entry* dentry = nullptr;
if (!System::IsExePath(path) && !System::IsPsfPath(path))
{
// Need to resolve hash games.
Error error;
std::unique_ptr<CDImage> image = CDImage::Open(path.c_str(), false, &error);
if (image)
dentry = GameDatabase::GetEntryForDisc(image.get());
else
ERROR_LOG("Failed to open '{}' for game properties: {}", path, error.GetDescription());
if (!dentry)
{
// Use the serial and hope for the best...
dentry = GameDatabase::GetEntryForSerial(serial);
}
}
std::string real_serial = dentry ? std::string(dentry->serial) : std::move(serial);
std::unique_ptr<INISettingsInterface> sif = System::GetGameSettingsInterface(dentry, real_serial, true, false);
std::unique_ptr<INISettingsInterface> sif =
System::GetGameSettingsInterface(entry->dbentry, entry->serial, true, false);
// check for an existing dialog with this serial
for (SettingsWindow* dialog : s_open_game_properties_dialogs)
SettingsWindow* sif_window = nullptr;
for (SettingsWindow* window : s_open_game_properties_dialogs)
{
if (dialog->isPerGameSettings() &&
static_cast<INISettingsInterface*>(dialog->getSettingsInterface())->GetPath() == sif->GetPath())
if (window->isPerGameSettings() && window->getSettingsInterface()->GetPath() == sif->GetPath())
{
dialog->show();
dialog->raise();
dialog->activateWindow();
dialog->setFocus();
if (category)
dialog->setCategory(category);
return dialog;
sif_window = window;
break;
}
}
SettingsWindow* dialog =
new SettingsWindow(path, std::move(title), std::move(real_serial), hash, region, dentry, std::move(sif));
dialog->show();
if (!sif_window)
sif_window = new SettingsWindow(entry, std::move(sif));
QtUtils::ShowOrRaiseWindow(sif_window);
if (category)
dialog->setCategory(category);
return dialog;
sif_window->setCategory(category);
return sif_window;
}
void SettingsWindow::closeGamePropertiesDialogs()

@ -23,6 +23,10 @@ enum class Trait : u32;
struct Entry;
} // namespace GameDatabase
namespace GameList {
struct Entry;
} // namespace GameList
class GameSummaryWidget;
class InterfaceSettingsWidget;
class BIOSSettingsWidget;
@ -45,12 +49,10 @@ class SettingsWindow final : public QWidget
public:
SettingsWindow();
SettingsWindow(const std::string& path, std::string title, std::string serial, GameHash hash, DiscRegion region,
const GameDatabase::Entry* entry, std::unique_ptr<INISettingsInterface> sif);
SettingsWindow(const GameList::Entry* entry, std::unique_ptr<INISettingsInterface> sif);
~SettingsWindow();
static SettingsWindow* openGamePropertiesDialog(const std::string& path, std::string title, std::string serial,
GameHash hash, DiscRegion region, const char* category = nullptr);
static SettingsWindow* openGamePropertiesDialog(const GameList::Entry* entry, const char* category = nullptr);
static void closeGamePropertiesDialogs();
// Helper for externally setting fields in game settings ini.
@ -103,7 +105,7 @@ public:
void removeSettingValue(const char* section, const char* key);
void saveAndReloadGameSettings();
void setGameTitle(std::string title);
void setGameTitle(std::string_view title);
bool hasGameTrait(GameDatabase::Trait trait);
Q_SIGNALS:

Loading…
Cancel
Save