mirror of https://github.com/PCSX2/pcsx2.git
GameList: Support adding custom title and region to files
This commit is contained in:
parent
be3ed181c1
commit
0256c4521d
|
@ -63,6 +63,11 @@ GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, SettingsDialo
|
|||
connect(m_ui.inputProfile, &QComboBox::currentIndexChanged, this, &GameSummaryWidget::onInputProfileChanged);
|
||||
connect(m_ui.verify, &QAbstractButton::clicked, this, &GameSummaryWidget::onVerifyClicked);
|
||||
connect(m_ui.searchHash, &QAbstractButton::clicked, this, &GameSummaryWidget::onSearchHashClicked);
|
||||
|
||||
bool has_custom_title = false, has_custom_region = false;
|
||||
GameList::CheckCustomAttributesForPath(m_entry_path, has_custom_title, has_custom_region);
|
||||
m_ui.restoreTitle->setEnabled(has_custom_title);
|
||||
m_ui.restoreRegion->setEnabled(has_custom_region);
|
||||
}
|
||||
|
||||
GameSummaryWidget::~GameSummaryWidget() = default;
|
||||
|
@ -88,6 +93,24 @@ void GameSummaryWidget::populateDetails(const GameList::Entry* entry)
|
|||
m_ui.inputProfile->setCurrentIndex(m_ui.inputProfile->findText(QString::fromStdString(profile.value())));
|
||||
else
|
||||
m_ui.inputProfile->setCurrentIndex(0);
|
||||
|
||||
connect(m_ui.title, &QLineEdit::editingFinished, this, [this]() {
|
||||
if (m_ui.title->isModified())
|
||||
{
|
||||
setCustomTitle(m_ui.title->text().toStdString());
|
||||
m_ui.title->setModified(false);
|
||||
}
|
||||
});
|
||||
connect(m_ui.restoreTitle, &QAbstractButton::clicked, this, [this]() {
|
||||
setCustomTitle("");
|
||||
});
|
||||
|
||||
connect(m_ui.region, &QComboBox::currentIndexChanged, this, [this](int index) {
|
||||
setCustomRegion(index);
|
||||
});
|
||||
connect(m_ui.restoreRegion, &QAbstractButton::clicked, this, [this]() {
|
||||
setCustomRegion(-1);
|
||||
});
|
||||
}
|
||||
|
||||
void GameSummaryWidget::populateDiscPath(const GameList::Entry* entry)
|
||||
|
@ -129,12 +152,7 @@ void GameSummaryWidget::onDiscPathChanged(const QString& value)
|
|||
|
||||
// force rescan of elf to update the serial
|
||||
g_main_window->rescanFile(m_entry_path);
|
||||
|
||||
// and re-fill our details (mainly the serial)
|
||||
auto lock = GameList::GetLock();
|
||||
const GameList::Entry* entry = GameList::GetEntryForPath(m_entry_path.c_str());
|
||||
if (entry)
|
||||
populateDetails(entry);
|
||||
repopulateCurrentDetails();
|
||||
}
|
||||
|
||||
void GameSummaryWidget::onDiscPathBrowseClicked()
|
||||
|
@ -353,3 +371,30 @@ void GameSummaryWidget::setVerifyResult(QString error)
|
|||
m_ui.verifyResult->setVisible(true);
|
||||
m_ui.searchHash->setVisible(true);
|
||||
}
|
||||
|
||||
void GameSummaryWidget::repopulateCurrentDetails()
|
||||
{
|
||||
auto lock = GameList::GetLock();
|
||||
const GameList::Entry* entry = GameList::GetEntryForPath(m_entry_path.c_str());
|
||||
if (entry)
|
||||
{
|
||||
populateDetails(entry);
|
||||
m_dialog->setWindowTitle(QString::fromStdString(entry->title));
|
||||
}
|
||||
}
|
||||
|
||||
void GameSummaryWidget::setCustomTitle(const std::string& text)
|
||||
{
|
||||
m_ui.restoreTitle->setEnabled(!text.empty());
|
||||
|
||||
GameList::SaveCustomTitleForPath(m_entry_path, text);
|
||||
repopulateCurrentDetails();
|
||||
}
|
||||
|
||||
void GameSummaryWidget::setCustomRegion(int region)
|
||||
{
|
||||
m_ui.restoreRegion->setEnabled(region >= 0);
|
||||
|
||||
GameList::SaveCustomRegionForPath(m_entry_path, region);
|
||||
repopulateCurrentDetails();
|
||||
}
|
||||
|
|
|
@ -47,6 +47,10 @@ private:
|
|||
void populateDiscPath(const GameList::Entry* entry);
|
||||
void populateTrackList(const GameList::Entry* entry);
|
||||
void setVerifyResult(QString error);
|
||||
void repopulateCurrentDetails();
|
||||
|
||||
void setCustomTitle(const std::string& text);
|
||||
void setCustomRegion(int region);
|
||||
|
||||
Ui::GameSummaryWidget m_ui;
|
||||
SettingsDialog* m_dialog;
|
||||
|
|
|
@ -34,11 +34,25 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="title">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="title">
|
||||
<property name="placeholderText">
|
||||
<string>Clear the line to restore the original title...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="restoreTitle">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Restore</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
|
@ -140,170 +154,178 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="region">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-B (Brazil)</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QComboBox" name="region">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-B (Brazil)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-C (China)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-HK (Hong Kong)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-J (Japan)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-K (Korea)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-T (Taiwan)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-U (US)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Other</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-A (Australia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-AF (South Africa)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-AU (Austria)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-BE (Belgium)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-E (Europe/Australia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-F (France)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-FI (Finland)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-G (Germany)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-GR (Greece)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-I (Italy)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-IN (India)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-M (Europe/Australia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-NL (Netherlands)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-NO (Norway)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-P (Portugal)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-PL (Poland)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-R (Russia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-S (Spain)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-SC (Scandinavia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-SW (Sweden)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-SWI (Switzerland)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-UK (United Kingdom)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="restoreRegion">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Restore</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-C (China)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-HK (Hong Kong)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-J (Japan)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-K (Korea)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-T (Taiwan)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">NTSC-U (US)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Other</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-A (Australia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-AF (South Africa)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-AU (Austria)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-BE (Belgium)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-E (Europe/Australia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-F (France)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-FI (Finland)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-G (Germany)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-GR (Greece)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-I (Italy)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-IN (India)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-M (Europe/Australia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-NL (Netherlands)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-NO (Norway)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-P (Portugal)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-PL (Poland)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-R (Russia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-S (Spain)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-SC (Scandinavia)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-SW (Sweden)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-SWI (Switzerland)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string extracomment="Leave the code as-is, translate the country's name.">PAL-UK (United Kingdom)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
|
@ -488,22 +510,22 @@
|
|||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="searchHash">
|
||||
<property name="text">
|
||||
<string>Search on Redump.org...</string>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Search on Redump.org...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -59,11 +59,12 @@ SettingsDialog::SettingsDialog(QWidget* parent)
|
|||
}
|
||||
|
||||
SettingsDialog::SettingsDialog(QWidget* parent, std::unique_ptr<SettingsInterface> sif, const GameList::Entry* game,
|
||||
std::string serial, u32 disc_crc)
|
||||
std::string serial, u32 disc_crc, QString filename)
|
||||
: QDialog(parent)
|
||||
, m_sif(std::move(sif))
|
||||
, m_serial(std::move(serial))
|
||||
, m_disc_crc(disc_crc)
|
||||
, m_filename(std::move(filename))
|
||||
{
|
||||
setupUi(game);
|
||||
|
||||
|
@ -80,9 +81,9 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
|
|||
if (isPerGameSettings())
|
||||
{
|
||||
QString summary = tr("<strong>Summary</strong><hr>This page shows details about the selected game. Changing the Input "
|
||||
"Profile will set the controller binding scheme for this game to whichever profile is chosen, instead "
|
||||
"of the default (Shared) configuration. The track list and dump verification can be used to determine "
|
||||
"if your disc image matches a known good dump. If it does not match, the game may be broken.");
|
||||
"Profile will set the controller binding scheme for this game to whichever profile is chosen, instead "
|
||||
"of the default (Shared) configuration. The track list and dump verification can be used to determine "
|
||||
"if your disc image matches a known good dump. If it does not match, the game may be broken.");
|
||||
if (game)
|
||||
{
|
||||
addWidget(new GameSummaryWidget(game, this, m_ui.settingsContainer), tr("Summary"),
|
||||
|
@ -153,7 +154,7 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
|
|||
addWidget(m_memory_card_settings = new MemoryCardSettingsWidget(this, m_ui.settingsContainer), tr("Memory Cards"),
|
||||
QStringLiteral("memcard-line"),
|
||||
tr("<strong>Memory Card Settings</strong><hr>Create and configure Memory Cards here.<br><br>Mouse over an option for "
|
||||
"additional information."));
|
||||
"additional information."));
|
||||
|
||||
addWidget(m_dev9_settings = new DEV9SettingsWidget(this, m_ui.settingsContainer), tr("Network & HDD"), QStringLiteral("global-line"),
|
||||
tr("<strong>Network & HDD Settings</strong><hr>These options control the network connectivity and internal HDD storage of the "
|
||||
|
@ -330,6 +331,18 @@ bool SettingsDialog::eventFilter(QObject* object, QEvent* event)
|
|||
return QDialog::eventFilter(object, event);
|
||||
}
|
||||
|
||||
void SettingsDialog::setWindowTitle(const QString& title)
|
||||
{
|
||||
if (m_filename.isEmpty())
|
||||
{
|
||||
QDialog::setWindowTitle(title);
|
||||
}
|
||||
else
|
||||
{
|
||||
QDialog::setWindowTitle(QStringLiteral("%1 [%2]").arg(title, m_filename));
|
||||
}
|
||||
}
|
||||
|
||||
bool SettingsDialog::getEffectiveBoolValue(const char* section, const char* key, bool default_value) const
|
||||
{
|
||||
bool value;
|
||||
|
@ -544,16 +557,12 @@ void SettingsDialog::openGamePropertiesDialog(const GameList::Entry* game, const
|
|||
}
|
||||
|
||||
std::string filename(VMManager::GetGameSettingsPath(serial, disc_crc));
|
||||
std::unique_ptr<INISettingsInterface> sif = std::make_unique<INISettingsInterface>(std::move(filename));
|
||||
std::unique_ptr<INISettingsInterface> sif = std::make_unique<INISettingsInterface>(filename);
|
||||
if (FileSystem::FileExists(sif->GetFileName().c_str()))
|
||||
sif->Load();
|
||||
|
||||
const QString window_title(tr("%1 [%2]")
|
||||
.arg(QtUtils::StringViewToQString(title))
|
||||
.arg(QtUtils::StringViewToQString(Path::GetFileName(sif->GetFileName()))));
|
||||
|
||||
SettingsDialog* dialog = new SettingsDialog(g_main_window, std::move(sif), game, std::move(serial), disc_crc);
|
||||
dialog->setWindowTitle(window_title);
|
||||
SettingsDialog* dialog = new SettingsDialog(g_main_window, std::move(sif), game, std::move(serial), disc_crc, QtUtils::StringViewToQString(Path::GetFileName(filename)));
|
||||
dialog->setWindowTitle(QtUtils::StringViewToQString(title));
|
||||
dialog->setModal(false);
|
||||
dialog->show();
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ class SettingsDialog final : public QDialog
|
|||
|
||||
public:
|
||||
explicit SettingsDialog(QWidget* parent);
|
||||
SettingsDialog(QWidget* parent, std::unique_ptr<SettingsInterface> sif, const GameList::Entry* game, std::string serial, u32 disc_crc);
|
||||
SettingsDialog(QWidget* parent, std::unique_ptr<SettingsInterface> sif, const GameList::Entry* game, std::string serial, u32 disc_crc, QString filename = QString());
|
||||
~SettingsDialog();
|
||||
|
||||
static void openGamePropertiesDialog(const GameList::Entry* game, const std::string_view& title, std::string serial, u32 disc_crc);
|
||||
|
@ -79,6 +79,8 @@ public:
|
|||
void registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text);
|
||||
bool eventFilter(QObject* object, QEvent* event) override;
|
||||
|
||||
void setWindowTitle(const QString& title);
|
||||
|
||||
QString getCategory() const;
|
||||
void setCategory(const char* category);
|
||||
|
||||
|
@ -145,6 +147,8 @@ private:
|
|||
QObject* m_current_help_widget = nullptr;
|
||||
QMap<QObject*, QString> m_widget_help_text_map;
|
||||
|
||||
QString m_filename;
|
||||
|
||||
std::string m_serial;
|
||||
u32 m_disc_crc;
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "Elfheader.h"
|
||||
#include "GameList.h"
|
||||
#include "Host.h"
|
||||
#include "INISettingsInterface.h"
|
||||
#include "VMManager.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
@ -75,10 +76,10 @@ namespace GameList
|
|||
|
||||
static bool GetGameListEntryFromCache(const std::string& path, GameList::Entry* entry);
|
||||
static void ScanDirectory(const char* path, bool recursive, bool only_cache, const std::vector<std::string>& excluded_paths,
|
||||
const PlayedTimeMap& played_time_map, ProgressCallback* progress);
|
||||
const PlayedTimeMap& played_time_map, const INISettingsInterface& custom_attributes_ini, ProgressCallback* progress);
|
||||
static bool AddFileFromCache(const std::string& path, std::time_t timestamp, const PlayedTimeMap& played_time_map);
|
||||
static bool ScanFile(
|
||||
std::string path, std::time_t timestamp, std::unique_lock<std::recursive_mutex>& lock, const PlayedTimeMap& played_time_map);
|
||||
static bool ScanFile(std::string path, std::time_t timestamp, std::unique_lock<std::recursive_mutex>& lock,
|
||||
const PlayedTimeMap& played_time_map, const INISettingsInterface& custom_attributes_ini);
|
||||
|
||||
static void LoadCache();
|
||||
static bool LoadEntriesFromCache(std::FILE* stream);
|
||||
|
@ -94,6 +95,8 @@ namespace GameList
|
|||
static PlayedTimeMap LoadPlayedTimeMap(const std::string& path);
|
||||
static PlayedTimeEntry UpdatePlayedTimeFile(
|
||||
const std::string& path, const std::string& serial, std::time_t last_time, std::time_t add_time);
|
||||
|
||||
static std::string GetCustomPropertiesFile();
|
||||
} // namespace GameList
|
||||
|
||||
static std::vector<GameList::Entry> s_entries;
|
||||
|
@ -586,7 +589,7 @@ static bool IsPathExcluded(const std::vector<std::string>& excluded_paths, const
|
|||
}
|
||||
|
||||
void GameList::ScanDirectory(const char* path, bool recursive, bool only_cache, const std::vector<std::string>& excluded_paths,
|
||||
const PlayedTimeMap& played_time_map, ProgressCallback* progress)
|
||||
const PlayedTimeMap& played_time_map, const INISettingsInterface& custom_attributes_ini, ProgressCallback* progress)
|
||||
{
|
||||
Console.WriteLn("Scanning %s%s", path, recursive ? " (recursively)" : "");
|
||||
|
||||
|
@ -619,7 +622,7 @@ void GameList::ScanDirectory(const char* path, bool recursive, bool only_cache,
|
|||
}
|
||||
|
||||
progress->SetFormattedStatusText("Scanning '%s'...", FileSystem::GetDisplayNameFromPath(ffd.FileName).c_str());
|
||||
ScanFile(std::move(ffd.FileName), ffd.ModificationTime, lock, played_time_map);
|
||||
ScanFile(std::move(ffd.FileName), ffd.ModificationTime, lock, played_time_map, custom_attributes_ini);
|
||||
progress->SetProgressValue(files_scanned);
|
||||
}
|
||||
|
||||
|
@ -648,8 +651,8 @@ bool GameList::AddFileFromCache(const std::string& path, std::time_t timestamp,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GameList::ScanFile(
|
||||
std::string path, std::time_t timestamp, std::unique_lock<std::recursive_mutex>& lock, const PlayedTimeMap& played_time_map)
|
||||
bool GameList::ScanFile(std::string path, std::time_t timestamp, std::unique_lock<std::recursive_mutex>& lock,
|
||||
const PlayedTimeMap& played_time_map, const INISettingsInterface& custom_attributes_ini)
|
||||
{
|
||||
// don't block UI while scanning
|
||||
lock.unlock();
|
||||
|
@ -675,13 +678,28 @@ bool GameList::ScanFile(
|
|||
return true;
|
||||
}
|
||||
|
||||
auto iter = played_time_map.find(entry.serial);
|
||||
const auto iter = played_time_map.find(entry.serial);
|
||||
if (iter != played_time_map.end())
|
||||
{
|
||||
entry.last_played_time = iter->second.last_played_time;
|
||||
entry.total_played_time = iter->second.total_played_time;
|
||||
}
|
||||
|
||||
auto custom_title = custom_attributes_ini.GetOptionalStringValue(entry.path.c_str(), "Title");
|
||||
if (custom_title)
|
||||
{
|
||||
entry.title = std::move(custom_title.value());
|
||||
}
|
||||
const auto custom_region = custom_attributes_ini.GetOptionalIntValue(entry.path.c_str(), "Region");
|
||||
if (custom_region)
|
||||
{
|
||||
const int custom_region_value = custom_region.value();
|
||||
if (custom_region_value >= 0 && custom_region_value < static_cast<int>(Region::Count))
|
||||
{
|
||||
entry.region = static_cast<Region>(custom_region_value);
|
||||
}
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
|
||||
// remove if present
|
||||
|
@ -764,6 +782,8 @@ void GameList::Refresh(bool invalidate_cache, bool only_cache, ProgressCallback*
|
|||
const std::vector<std::string> dirs(Host::GetBaseStringListSetting("GameList", "Paths"));
|
||||
const std::vector<std::string> recursive_dirs(Host::GetBaseStringListSetting("GameList", "RecursivePaths"));
|
||||
const PlayedTimeMap played_time(LoadPlayedTimeMap(GetPlayedTimeFile()));
|
||||
INISettingsInterface custom_attributes_ini(GetCustomPropertiesFile());
|
||||
custom_attributes_ini.Load();
|
||||
|
||||
if (!dirs.empty() || !recursive_dirs.empty())
|
||||
{
|
||||
|
@ -777,7 +797,7 @@ void GameList::Refresh(bool invalidate_cache, bool only_cache, ProgressCallback*
|
|||
if (progress->IsCancelled())
|
||||
break;
|
||||
|
||||
ScanDirectory(dir.c_str(), false, only_cache, excluded_paths, played_time, progress);
|
||||
ScanDirectory(dir.c_str(), false, only_cache, excluded_paths, played_time, custom_attributes_ini, progress);
|
||||
progress->SetProgressValue(++directory_counter);
|
||||
}
|
||||
for (const std::string& dir : recursive_dirs)
|
||||
|
@ -785,7 +805,7 @@ void GameList::Refresh(bool invalidate_cache, bool only_cache, ProgressCallback*
|
|||
if (progress->IsCancelled())
|
||||
break;
|
||||
|
||||
ScanDirectory(dir.c_str(), true, only_cache, excluded_paths, played_time, progress);
|
||||
ScanDirectory(dir.c_str(), true, only_cache, excluded_paths, played_time, custom_attributes_ini, progress);
|
||||
progress->SetProgressValue(++directory_counter);
|
||||
}
|
||||
}
|
||||
|
@ -804,6 +824,8 @@ bool GameList::RescanPath(const std::string& path)
|
|||
std::unique_lock lock(s_mutex);
|
||||
|
||||
const PlayedTimeMap played_time(LoadPlayedTimeMap(GetPlayedTimeFile()));
|
||||
INISettingsInterface custom_attributes_ini(GetCustomPropertiesFile());
|
||||
custom_attributes_ini.Load();
|
||||
|
||||
{
|
||||
// cancel if excluded
|
||||
|
@ -813,7 +835,7 @@ bool GameList::RescanPath(const std::string& path)
|
|||
}
|
||||
|
||||
// re-scan!
|
||||
if (!ScanFile(path, sd.ModificationTime, lock, played_time))
|
||||
if (!ScanFile(path, sd.ModificationTime, lock, played_time, custom_attributes_ini))
|
||||
return true;
|
||||
|
||||
// update cache.. this is far from ideal, but since everything's variable length, all we can do.
|
||||
|
@ -1319,3 +1341,74 @@ bool GameList::DownloadCovers(const std::vector<std::string>& url_templates, boo
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GameList::GetCustomPropertiesFile()
|
||||
{
|
||||
return Path::Combine(EmuFolders::Settings, "custom_properties.ini");
|
||||
}
|
||||
|
||||
void GameList::CheckCustomAttributesForPath(const std::string& path, bool& has_custom_title, bool& has_custom_region)
|
||||
{
|
||||
INISettingsInterface names(GetCustomPropertiesFile());
|
||||
if (names.Load())
|
||||
{
|
||||
has_custom_title = names.ContainsValue(path.c_str(), "Title");
|
||||
has_custom_region = names.ContainsValue(path.c_str(), "Region");
|
||||
}
|
||||
}
|
||||
|
||||
void GameList::SaveCustomTitleForPath(const std::string& path, const std::string& custom_title)
|
||||
{
|
||||
INISettingsInterface names(GetCustomPropertiesFile());
|
||||
names.Load();
|
||||
|
||||
if (!custom_title.empty())
|
||||
{
|
||||
names.SetStringValue(path.c_str(), "Title", custom_title.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
names.DeleteValue(path.c_str(), "Title");
|
||||
}
|
||||
|
||||
if (names.Save())
|
||||
{
|
||||
// Let the cache update by rescanning
|
||||
RescanPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
void GameList::SaveCustomRegionForPath(const std::string& path, int custom_region)
|
||||
{
|
||||
INISettingsInterface names(GetCustomPropertiesFile());
|
||||
names.Load();
|
||||
|
||||
if (custom_region >= 0)
|
||||
{
|
||||
names.SetIntValue(path.c_str(), "Region", custom_region);
|
||||
}
|
||||
else
|
||||
{
|
||||
names.DeleteValue(path.c_str(), "Region");
|
||||
}
|
||||
|
||||
if (names.Save())
|
||||
{
|
||||
// Let the cache update by rescanning
|
||||
RescanPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
std::string GameList::GetCustomTitleForPath(const std::string& path)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
std::unique_lock lock(s_mutex);
|
||||
const GameList::Entry* entry = GetEntryForPath(path.c_str());
|
||||
if (entry)
|
||||
{
|
||||
ret = entry->title;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -154,4 +154,10 @@ namespace GameList
|
|||
/// the use_serial parameter. save_callback optionall takes the entry and the path the new cover is saved to.
|
||||
bool DownloadCovers(const std::vector<std::string>& url_templates, bool use_serial = false, ProgressCallback* progress = nullptr,
|
||||
std::function<void(const Entry*, std::string)> save_callback = {});
|
||||
|
||||
// Custom properties support
|
||||
void CheckCustomAttributesForPath(const std::string& path, bool& has_custom_title, bool& has_custom_region);
|
||||
void SaveCustomTitleForPath(const std::string& path, const std::string& custom_title);
|
||||
void SaveCustomRegionForPath(const std::string& path, int custom_region);
|
||||
std::string GetCustomTitleForPath(const std::string& path);
|
||||
} // namespace GameList
|
||||
|
|
|
@ -849,19 +849,22 @@ void VMManager::UpdateDiscDetails(bool booting)
|
|||
|
||||
SaveSessionTime(old_serial);
|
||||
|
||||
std::string custom_title = GameList::GetCustomTitleForPath(CDVDsys_GetFile(CDVDsys_GetSourceType()));
|
||||
if (serial_is_valid)
|
||||
{
|
||||
if (const GameDatabaseSchema::GameEntry* game = GameDatabase::findGame(s_disc_serial))
|
||||
{
|
||||
std::string game_title = custom_title.empty() ? game->name : std::move(custom_title);
|
||||
|
||||
// Append the ELF override if we're using it with a disc.
|
||||
if (!s_elf_override.empty())
|
||||
{
|
||||
title = fmt::format(
|
||||
"{} [{}]", game->name, Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(s_elf_override)));
|
||||
"{} [{}]", game_title, Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(s_elf_override)));
|
||||
}
|
||||
else
|
||||
{
|
||||
title = game->name;
|
||||
title = std::move(game_title);
|
||||
}
|
||||
|
||||
memcardFilters = game->memcardFiltersAsString();
|
||||
|
@ -872,6 +875,11 @@ void VMManager::UpdateDiscDetails(bool booting)
|
|||
}
|
||||
}
|
||||
|
||||
if (title.empty())
|
||||
{
|
||||
title = std::move(custom_title);
|
||||
}
|
||||
|
||||
if (title.empty())
|
||||
{
|
||||
if (!s_disc_serial.empty())
|
||||
|
|
Loading…
Reference in New Issue