Qt: Add copy global settings/clear per-game settings

This commit is contained in:
Stenzek 2023-09-04 21:14:39 +10:00 committed by Connor McLaughlin
parent c16836e7c0
commit 7b45e9296a
9 changed files with 234 additions and 22 deletions

View File

@ -169,3 +169,60 @@ void SettingsSaveWrapper::_EnumEntry(const char* section, const char* var, int&
const int index = (value < 0 || value >= cnt) ? defvalue : value;
m_si.SetStringValue(section, var, enumArray[index]);
}
SettingsClearWrapper::SettingsClearWrapper(SettingsInterface& si)
: SettingsWrapper(si)
{
}
bool SettingsClearWrapper::IsLoading() const
{
return false;
}
bool SettingsClearWrapper::IsSaving() const
{
return true;
}
void SettingsClearWrapper::Entry(const char* section, const char* var, int& value, const int defvalue /*= 0*/)
{
m_si.DeleteValue(section, var);
}
void SettingsClearWrapper::Entry(const char* section, const char* var, uint& value, const uint defvalue /*= 0*/)
{
m_si.DeleteValue(section, var);
}
void SettingsClearWrapper::Entry(const char* section, const char* var, bool& value, const bool defvalue /*= false*/)
{
m_si.DeleteValue(section, var);
}
void SettingsClearWrapper::Entry(const char* section, const char* var, float& value, const float defvalue /*= 0.0*/)
{
m_si.DeleteValue(section, var);
}
void SettingsClearWrapper::Entry(const char* section, const char* var, std::string& value, const std::string& default_value /*= std::string()*/)
{
m_si.DeleteValue(section, var);
}
bool SettingsClearWrapper::EntryBitBool(const char* section, const char* var, bool value, const bool defvalue /*= false*/)
{
m_si.DeleteValue(section, var);
return defvalue;
}
int SettingsClearWrapper::EntryBitfield(const char* section, const char* var, int value, const int defvalue /*= 0*/)
{
m_si.DeleteValue(section, var);
return defvalue;
}
void SettingsClearWrapper::_EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue)
{
m_si.DeleteValue(section, var);
}

View File

@ -96,6 +96,27 @@ protected:
void _EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue) override;
};
class SettingsClearWrapper final : public SettingsWrapper
{
public:
SettingsClearWrapper(SettingsInterface& si);
bool IsLoading() const override;
bool IsSaving() const override;
void Entry(const char* section, const char* var, int& value, const int defvalue = 0) override;
void Entry(const char* section, const char* var, uint& value, const uint defvalue = 0) override;
void Entry(const char* section, const char* var, bool& value, const bool defvalue = false) override;
void Entry(const char* section, const char* var, float& value, const float defvalue = 0.0) override;
void Entry(const char* section, const char* var, std::string& value, const std::string& default_value = std::string()) override;
bool EntryBitBool(const char* section, const char* var, bool value, const bool defvalue = false) override;
int EntryBitfield(const char* section, const char* var, int value, const int defvalue = 0) override;
protected:
void _EnumEntry(const char* section, const char* var, int& value, const char* const* enumArray, int defvalue) override;
};
#define SettingsWrapSection(section) const char* CURRENT_SETTINGS_SECTION = section;
#define SettingsWrapEntry(var) wrap.Entry(CURRENT_SETTINGS_SECTION, #var, var, var)
#define SettingsWrapEntryEx(var, name) wrap.Entry(CURRENT_SETTINGS_SECTION, name, var, var)

View File

@ -166,7 +166,7 @@ void EmulationSettingsWidget::initializeSpeedCombo(QComboBox* cb, const char* se
if (m_dialog->isPerGameSettings())
{
cb->addItem(tr("Use Global Setting [%1%]").arg(value * 100.0f, 0, 'f', 0));
if (!m_dialog->getSettingsInterface()->GetFloatValue(key, section, &value))
if (!m_dialog->getSettingsInterface()->GetFloatValue(section, key, &value))
{
// set to something without data
value = -1.0f;

View File

@ -58,11 +58,12 @@ SettingsDialog::SettingsDialog(QWidget* parent)
setupUi(nullptr);
}
SettingsDialog::SettingsDialog(QWidget* parent, std::unique_ptr<SettingsInterface> sif, const GameList::Entry* game,
SettingsDialog::SettingsDialog(QWidget* parent, std::unique_ptr<INISettingsInterface> sif, const GameList::Entry* game,
std::string serial, u32 disc_crc, QString filename)
: QDialog(parent)
, m_sif(std::move(sif))
, m_filename(std::move(filename))
, m_game_list_filename(game ? game->path : std::string())
, m_serial(std::move(serial))
, m_disc_crc(disc_crc)
{
@ -71,6 +72,11 @@ SettingsDialog::SettingsDialog(QWidget* parent, std::unique_ptr<SettingsInterfac
s_open_game_properties_dialogs.push_back(this);
}
SettingsInterface* SettingsDialog::getSettingsInterface() const
{
return m_sif.get();
}
void SettingsDialog::setupUi(const GameList::Entry* game)
{
const bool show_advanced_settings = QtHost::ShouldShowAdvancedSettings();
@ -98,6 +104,21 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
}
m_ui.restoreDefaultsButton->setVisible(false);
m_ui.footerLayout->removeWidget(m_ui.restoreDefaultsButton);
m_ui.restoreDefaultsButton->deleteLater();
m_ui.restoreDefaultsButton = nullptr;
}
else
{
m_ui.copyGlobalSettingsButton->setVisible(false);
m_ui.footerLayout->removeWidget(m_ui.copyGlobalSettingsButton);
m_ui.copyGlobalSettingsButton->deleteLater();
m_ui.copyGlobalSettingsButton = nullptr;
m_ui.clearGameSettingsButton->setVisible(false);
m_ui.footerLayout->removeWidget(m_ui.clearGameSettingsButton);
m_ui.clearGameSettingsButton->deleteLater();
m_ui.clearGameSettingsButton = nullptr;
}
addWidget(m_interface_settings = new InterfaceSettingsWidget(this, m_ui.settingsContainer), tr("Interface"),
@ -213,7 +234,12 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
m_ui.helpText->setText(m_category_help_text[0]);
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &SettingsDialog::onCategoryCurrentRowChanged);
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::close);
connect(m_ui.restoreDefaultsButton, &QPushButton::clicked, this, &SettingsDialog::onRestoreDefaultsClicked);
if (m_ui.restoreDefaultsButton)
connect(m_ui.restoreDefaultsButton, &QPushButton::clicked, this, &SettingsDialog::onRestoreDefaultsClicked);
if (m_ui.copyGlobalSettingsButton)
connect(m_ui.copyGlobalSettingsButton, &QPushButton::clicked, this, &SettingsDialog::onCopyGlobalSettingsClicked);
if (m_ui.clearGameSettingsButton)
connect(m_ui.clearGameSettingsButton, &QPushButton::clicked, this, &SettingsDialog::onClearSettingsClicked);
}
SettingsDialog::~SettingsDialog()
@ -274,6 +300,71 @@ void SettingsDialog::onRestoreDefaultsClicked()
g_main_window->resetSettings(ui_cb->isChecked());
}
void SettingsDialog::onCopyGlobalSettingsClicked()
{
if (!isPerGameSettings())
return;
if (QMessageBox::question(this, tr("PCSX2 Settings"),
tr("The configuration for this game will be replaced by the current global settings.\n\nAny current setting values will be "
"overwritten.\n\nDo you want to continue?"),
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
{
return;
}
{
auto lock = Host::GetSettingsLock();
Pcsx2Config::CopyConfiguration(m_sif.get(), *Host::Internal::GetBaseSettingsLayer());
}
m_sif->Save();
g_emu_thread->reloadGameSettings();
QMessageBox::information(reopen(), tr("PCSX2 Settings"), tr("Per-game configuration copied from global settings."));
}
void SettingsDialog::onClearSettingsClicked()
{
if (!isPerGameSettings())
return;
if (QMessageBox::question(this, tr("PCSX2 Settings"),
tr("The configuration for this game will be cleared.\n\nAny current setting values will be lost.\n\nDo you want to continue?"),
QMessageBox::Yes, QMessageBox::No) != QMessageBox::Yes)
{
return;
}
Pcsx2Config::ClearConfiguration(m_sif.get());
m_sif->Save();
g_emu_thread->reloadGameSettings();
QMessageBox::information(reopen(), tr("PCSX2 Settings"), tr("Per-game configuration cleared."));
}
SettingsDialog* SettingsDialog::reopen()
{
// This doesn't work for global settings, because MainWindow maintains a pointer.
if (!m_sif)
return this;
close();
std::unique_ptr<INISettingsInterface> new_sif = std::make_unique<INISettingsInterface>(m_sif->GetFileName());
if (FileSystem::FileExists(new_sif->GetFileName().c_str()))
new_sif->Load();
auto lock = GameList::GetLock();
const GameList::Entry* game = m_game_list_filename.empty() ? nullptr : GameList::GetEntryForPath(m_game_list_filename.c_str());
SettingsDialog* dlg = new SettingsDialog(g_main_window, std::move(new_sif), game, m_serial, m_disc_crc, m_filename);
dlg->QDialog::setWindowTitle(windowTitle());
dlg->setModal(false);
dlg->show();
return dlg;
}
void SettingsDialog::addWidget(QWidget* widget, QString title, QString icon, QString help_text)
{
const int index = m_ui.settingsCategory->count();
@ -566,3 +657,4 @@ void SettingsDialog::openGamePropertiesDialog(const GameList::Entry* game, const
dialog->setModal(false);
dialog->show();
}

View File

@ -51,12 +51,13 @@ 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, QString filename = QString());
SettingsDialog(QWidget* parent, std::unique_ptr<INISettingsInterface> 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);
__fi SettingsInterface* getSettingsInterface() const { return m_sif.get(); }
SettingsInterface* getSettingsInterface() const;
__fi bool isPerGameSettings() const { return static_cast<bool>(m_sif); }
__fi const std::string& getSerial() const { return m_serial; }
__fi u32 getDiscCRC() const { return m_disc_crc; }
@ -108,6 +109,8 @@ Q_SIGNALS:
private Q_SLOTS:
void onCategoryCurrentRowChanged(int row);
void onRestoreDefaultsClicked();
void onCopyGlobalSettingsClicked();
void onClearSettingsClicked();
protected:
void closeEvent(QCloseEvent*) override;
@ -122,7 +125,9 @@ private:
void addWidget(QWidget* widget, QString title, QString icon, QString help_text);
std::unique_ptr<SettingsInterface> m_sif;
SettingsDialog* reopen();
std::unique_ptr<INISettingsInterface> m_sif;
Ui::SettingsDialog m_ui;
@ -149,6 +154,7 @@ private:
QString m_filename;
std::string m_game_list_filename;
std::string m_serial;
u32 m_disc_crc;
};

View File

@ -81,7 +81,7 @@
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="footerLayout">
<item>
<widget class="QPushButton" name="restoreDefaultsButton">
<property name="text">
@ -89,6 +89,20 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="copyGlobalSettingsButton">
<property name="text">
<string>Copy Global Settings</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearGameSettingsButton">
<property name="text">
<string>Clear Settings</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">

View File

@ -1350,6 +1350,7 @@ struct Pcsx2Config
Pcsx2Config();
void LoadSave(SettingsWrapper& wrap);
void LoadSaveCore(SettingsWrapper& wrap);
void LoadSaveMemcards(SettingsWrapper& wrap);
/// Reloads options affected by patches.
@ -1366,6 +1367,12 @@ struct Pcsx2Config
/// Copies runtime configuration settings (e.g. frame limiter state).
void CopyRuntimeConfig(Pcsx2Config& cfg);
/// Copies configuration from one file to another. Does not copy controller settings.
static void CopyConfiguration(SettingsInterface* dest_si, SettingsInterface& src_si);
/// Clears all core keys from the specified interface.
static void ClearConfiguration(SettingsInterface* dest_si);
};
extern Pcsx2Config EmuConfig;

View File

@ -2490,15 +2490,7 @@ void FullscreenUI::DoCopyGameSettings()
if (!s_game_settings_interface)
return;
Pcsx2Config temp;
{
SettingsLoadWrapper wrapper(*GetEditingSettingsInterface(false));
temp.LoadSave(wrapper);
}
{
SettingsSaveWrapper wrapper(*s_game_settings_interface.get());
temp.LoadSave(wrapper);
}
Pcsx2Config::CopyConfiguration(s_game_settings_interface.get(), *GetEditingSettingsInterface(false));
SetSettingsChanged(s_game_settings_interface.get());
@ -2511,9 +2503,7 @@ void FullscreenUI::DoClearGameSettings()
if (!s_game_settings_interface)
return;
s_game_settings_interface->Clear();
if (!s_game_settings_interface->GetFileName().empty())
FileSystem::DeleteFilePath(s_game_settings_interface->GetFileName().c_str());
Pcsx2Config::ClearConfiguration(s_game_settings_interface.get());
SetSettingsChanged(s_game_settings_interface.get());

View File

@ -1485,7 +1485,7 @@ Pcsx2Config::Pcsx2Config()
PINESlot = 28011;
}
void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
void Pcsx2Config::LoadSaveCore(SettingsWrapper& wrap)
{
// Switch the rounding mode back to the system default for loading settings.
// That way, we'll get exactly the same values as what we loaded when we first started.
@ -1531,8 +1531,6 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
Debugger.LoadSave(wrap);
Trace.LoadSave(wrap);
USB.LoadSave(wrap);
Pad.LoadSave(wrap);
#ifdef ENABLE_ACHIEVEMENTS
Achievements.LoadSave(wrap);
@ -1560,6 +1558,13 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
SSE_MXCSR::SetCurrent(prev_mxcsr);
}
void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
{
LoadSaveCore(wrap);
USB.LoadSave(wrap);
Pad.LoadSave(wrap);
}
void Pcsx2Config::LoadSaveMemcards(SettingsWrapper& wrap)
{
for (uint slot = 0; slot < 2; ++slot)
@ -1635,6 +1640,26 @@ void Pcsx2Config::CopyRuntimeConfig(Pcsx2Config& cfg)
}
}
void Pcsx2Config::CopyConfiguration(SettingsInterface* dest_si, SettingsInterface& src_si)
{
Pcsx2Config temp;
{
SettingsLoadWrapper wrapper(src_si);
temp.LoadSaveCore(wrapper);
}
{
SettingsSaveWrapper wrapper(*dest_si);
temp.LoadSaveCore(wrapper);
}
}
void Pcsx2Config::ClearConfiguration(SettingsInterface* dest_si)
{
Pcsx2Config temp;
SettingsClearWrapper wrapper(*dest_si);
temp.LoadSaveCore(wrapper);
}
bool EmuFolders::InitializeCriticalFolders()
{
SetAppRoot();