Qt: Allow editing folder settings

This commit is contained in:
Connor McLaughlin 2022-06-14 20:05:11 +10:00 committed by refractionpcsx2
parent a07ef0f5ee
commit 02d3c93c2c
10 changed files with 141 additions and 52 deletions

View File

@ -412,6 +412,17 @@ void EmuThread::reloadGameSettings()
}
}
void EmuThread::updateEmuFolders()
{
if (!isOnEmuThread())
{
QMetaObject::invokeMethod(this, &EmuThread::updateEmuFolders, Qt::QueuedConnection);
return;
}
Host::Internal::UpdateEmuFolders();
}
void EmuThread::loadOurSettings()
{
m_verbose_status = Host::GetBaseBoolSettingValue("UI", "VerboseStatusBar", false);

View File

@ -70,6 +70,7 @@ public Q_SLOTS:
void setSurfaceless(bool surfaceless);
void applySettings();
void reloadGameSettings();
void updateEmuFolders();
void toggleSoftwareRendering();
void switchRenderer(GSRendererType renderer);
void changeDisc(const QString& path);

View File

@ -228,14 +228,6 @@ void QtHost::SetDataDirectory()
EmuFolders::DataRoot = EmuFolders::AppRoot;
}
void QtHost::UpdateFolders()
{
// TODO: This should happen with the VM thread paused.
auto lock = Host::GetSettingsLock();
EmuFolders::LoadConfig(*s_base_settings_interface.get());
EmuFolders::EnsureFoldersExist();
}
bool QtHost::InitializeConfig()
{
if (!SetCriticalFolders())

View File

@ -40,8 +40,6 @@ namespace QtHost
bool Initialize();
void Shutdown();
void UpdateFolders();
/// Sets batch mode (exit after game shutdown).
bool InBatchMode();
void SetBatchMode(bool enabled);

View File

@ -20,17 +20,23 @@
#include <QtCore/QtCore>
#include <QtGui/QAction>
#include <QtWidgets/QAbstractButton>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDoubleSpinBox>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QSlider>
#include <QtWidgets/QSpinBox>
#include "common/Path.h"
#include "pcsx2/Config.h"
#include "pcsx2/HostSettings.h"
#include "EmuThread.h"
#include "QtHost.h"
#include "QtUtils.h"
#include "Settings/SettingsDialog.h"
namespace SettingWidgetBinder
@ -228,7 +234,7 @@ namespace SettingWidgetBinder
static std::optional<QString> getNullableStringValue(const QCheckBox* widget)
{
return (widget->checkState() == Qt::PartiallyChecked) ?
std::nullopt :
std::nullopt :
std::optional<QString>(widget->isChecked() ? QStringLiteral("1") : QStringLiteral("0"));
}
static void setNullableStringValue(QCheckBox* widget, std::optional<QString> value)
@ -769,4 +775,70 @@ namespace SettingWidgetBinder
}
}
template <typename WidgetType>
static void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget,
QAbstractButton* browse_button, QAbstractButton* open_button, QAbstractButton* reset_button,
std::string section, std::string key, std::string default_value)
{
using Accessor = SettingAccessor<WidgetType>;
std::string current_path(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str()));
if (!Path::IsAbsolute(current_path))
current_path = Path::Combine(EmuFolders::DataRoot, current_path);
const QString value(QString::fromStdString(current_path));
Accessor::setStringValue(widget, value);
// if we're doing per-game settings, disable the widget, we only allow folder changes in the base config
if (sif)
{
widget->setEnabled(false);
if (browse_button)
browse_button->setEnabled(false);
if (reset_button)
reset_button->setEnabled(false);
return;
}
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
const std::string new_value(Accessor::getStringValue(widget).toStdString());
if (!new_value.empty())
{
std::string relative_path(Path::MakeRelative(new_value, EmuFolders::DataRoot));
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), relative_path.c_str());
}
else
{
QtHost::RemoveBaseSettingValue(section.c_str(), key.c_str());
}
g_emu_thread->updateEmuFolders();
});
if (browse_button)
{
QObject::connect(browse_button, &QAbstractButton::clicked, browse_button, [widget, key]() {
const QString path(QDir::toNativeSeparators(QFileDialog::getExistingDirectory(QtUtils::GetRootWidget(widget),
qApp->translate("SettingWidgetBinder", "Select folder for %1").arg(QString::fromStdString(key)))));
if (path.isEmpty())
return;
Accessor::setStringValue(widget, path);
});
}
if (open_button)
{
QObject::connect(open_button, &QAbstractButton::clicked, open_button, [widget]() {
QString path(Accessor::getStringValue(widget));
if (!path.isEmpty())
QtUtils::OpenURL(QtUtils::GetRootWidget(widget), QUrl::fromLocalFile(path));
});
}
if (reset_button)
{
QObject::connect(reset_button, &QAbstractButton::clicked, reset_button, [widget, default_value = std::move(default_value)]() {
Accessor::setStringValue(widget, QString::fromStdString(Path::Combine(EmuFolders::AppRoot, default_value)));
});
}
}
} // namespace SettingWidgetBinder

View File

@ -38,28 +38,17 @@ BIOSSettingsWidget::BIOSSettingsWidget(SettingsDialog* dialog, QWidget* parent)
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBoot, "EmuCore", "EnableFastBoot", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.patchRegion, "EmuCore", "PatchBios", false);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.regionComboBox, "EmuCore", "PatchRegion", BiosZoneStrings, BiosZoneBytes, BiosZoneBytes[0]);
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.searchDirectory, m_ui.browseSearchDirectory, m_ui.openSearchDirectory,
m_ui.resetSearchDirectory, "Folders", "Bios", "bios");
dialog->registerWidgetHelp(m_ui.patchRegion, tr("Patch Region"),tr("Unchecked"),
dialog->registerWidgetHelp(m_ui.patchRegion, tr("Patch Region"), tr("Unchecked"),
tr("Patches the BIOS region byte in ROM. Not recommended unless you really know what you're doing."));
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"),
tr("Patches the BIOS to skip the console's boot animation."));
updateSearchDirectory();
refreshList();
connect(m_ui.searchDirectory, &QLineEdit::textChanged, [this](const QString& text) {
QtHost::SetBaseStringSettingValue("Folders", "Bios", text.toUtf8().constData());
QtHost::UpdateFolders();
refreshList();
});
connect(m_ui.resetSearchDirectory, &QPushButton::clicked, [this]() {
QtHost::RemoveBaseSettingValue("Folders", "Bios");
QtHost::UpdateFolders();
updateSearchDirectory();
refreshList();
});
connect(m_ui.browseSearchDirectory, &QPushButton::clicked, this, &BIOSSettingsWidget::browseSearchDirectory);
connect(m_ui.openSearchDirectory, &QPushButton::clicked, this, &BIOSSettingsWidget::openSearchDirectory);
connect(m_ui.searchDirectory, &QLineEdit::textChanged, this, &BIOSSettingsWidget::refreshList);
connect(m_ui.refresh, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);
connect(m_ui.fileList, &QTreeWidget::currentItemChanged, this, &BIOSSettingsWidget::listItemChanged);
@ -89,27 +78,6 @@ void BIOSSettingsWidget::refreshList()
m_refresh_thread->start();
}
void BIOSSettingsWidget::browseSearchDirectory()
{
QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(
QtUtils::GetRootWidget(this), tr("Select Directory"), m_ui.searchDirectory->text()));
if (directory.isEmpty())
return;
m_ui.searchDirectory->setText(directory);
}
void BIOSSettingsWidget::openSearchDirectory()
{
QtUtils::OpenURL(this, QUrl::fromLocalFile(m_ui.searchDirectory->text()));
}
void BIOSSettingsWidget::updateSearchDirectory()
{
// this will generate a full path
m_ui.searchDirectory->setText(QString::fromStdString(EmuFolders::Bios));
}
void BIOSSettingsWidget::listRefreshed(const QVector<BIOSInfo>& items)
{
const std::string selected_bios(Host::GetBaseStringSettingValue("Filenames", "BIOS"));

View File

@ -47,9 +47,6 @@ public:
private Q_SLOTS:
void refreshList();
void browseSearchDirectory();
void openSearchDirectory();
void updateSearchDirectory();
void listItemChanged(const QTreeWidgetItem* current, const QTreeWidgetItem* previous);
void listRefreshed(const QVector<BIOSInfo>& items);

View File

@ -188,7 +188,7 @@
</layout>
</widget>
<resources>
<include location="resources/resources.qrc"/>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -15,9 +15,14 @@
#include "PrecompiledHeader.h"
#include "common/Assertions.h"
#include "Frontend/LayeredSettingsInterface.h"
#include "GS.h"
#include "GS/Renderers/HW/GSTextureReplacements.h"
#include "Host.h"
#include "HostSettings.h"
#include "Frontend/LayeredSettingsInterface.h"
#include "MemoryCardFile.h"
#include "Sio.h"
#include "VMManager.h"
static std::mutex s_settings_mutex;
static LayeredSettingsInterface s_layered_settings_interface;
@ -202,3 +207,45 @@ void Host::Internal::SetInputSettingsLayer(SettingsInterface* sif)
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.SetLayer(LayeredSettingsInterface::LAYER_INPUT, sif);
}
void Host::Internal::UpdateEmuFolders()
{
const std::string old_cheats_directory(EmuFolders::Cheats);
const std::string old_cheats_ws_directory(EmuFolders::CheatsWS);
const std::string old_cheats_ni_directory(EmuFolders::CheatsNI);
const std::string old_memcards_directory(EmuFolders::MemoryCards);
const std::string old_textures_directory(EmuFolders::Textures);
EmuFolders::LoadConfig(*GetBaseSettingsLayer());
EmuFolders::EnsureFoldersExist();
if (VMManager::HasValidVM())
{
if (EmuFolders::Cheats != old_cheats_directory ||
EmuFolders::CheatsWS != old_cheats_ws_directory ||
EmuFolders::CheatsNI != old_cheats_ni_directory)
{
VMManager::ReloadPatches(true, true);
}
if (EmuFolders::MemoryCards != old_memcards_directory)
{
FileMcd_EmuClose();
FileMcd_EmuOpen();
for (u32 port = 0; port < 2; port++)
{
for (u32 slot = 0; slot < 4; slot++)
SetForceMcdEjectTimeoutNow(port, slot);
}
}
if (EmuFolders::Textures != old_textures_directory)
{
GetMTGS().RunOnGSThread([]() {
if (VMManager::HasValidVM())
GSTextureReplacements::ReloadReplacementMap();
});
}
}
}

View File

@ -79,5 +79,8 @@ namespace Host
/// Sets the input profile settings layer. Called by VMManager when the game changes.
void SetInputSettingsLayer(SettingsInterface* sif);
/// Updates the variables in the EmuFolders namespace, reloading subsystems if needed. Must call with the lock held.
void UpdateEmuFolders();
} // namespace Internal
} // namespace Host