Qt: Implement settings reset

This commit is contained in:
Connor McLaughlin 2022-09-07 17:44:10 +10:00 committed by refractionpcsx2
parent d86abebb50
commit e4df563811
35 changed files with 771 additions and 491 deletions

View File

@ -454,7 +454,8 @@ void AutoUpdaterDialog::checkIfUpdateNeeded()
void AutoUpdaterDialog::skipThisUpdateClicked()
{
QtHost::SetBaseStringSettingValue("AutoUpdater", "LastVersion", m_latest_version.toUtf8().constData());
Host::SetBaseStringSettingValue("AutoUpdater", "LastVersion", m_latest_version.toUtf8().constData());
Host::CommitBaseSettingChanges();
done(0);
}

View File

@ -347,7 +347,8 @@ void GameListWidget::onTableViewHeaderSortIndicatorChanged(int, Qt::SortOrder)
void GameListWidget::listZoom(float delta)
{
const float new_scale = std::clamp(m_model->getCoverScale() + delta, MIN_SCALE, MAX_SCALE);
QtHost::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
Host::CommitBaseSettingChanges();
m_model->setCoverScale(new_scale);
m_model->updateCacheSize(width(), height());
updateListFont();
@ -368,7 +369,8 @@ void GameListWidget::gridIntScale(int int_scale)
{
const float new_scale = std::clamp(static_cast<float>(int_scale) / 100.0f, MIN_SCALE, MAX_SCALE);
QtHost::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
Host::SetBaseFloatSettingValue("UI", "GameListCoverArtScale", new_scale);
Host::CommitBaseSettingChanges();
m_model->setCoverScale(new_scale);
m_model->updateCacheSize(width(), height());
updateListFont();
@ -389,7 +391,8 @@ void GameListWidget::showGameList()
return;
}
QtHost::SetBaseBoolSettingValue("UI", "GameListGridView", false);
Host::SetBaseBoolSettingValue("UI", "GameListGridView", false);
Host::CommitBaseSettingChanges();
m_ui.stack->setCurrentIndex(0);
resizeTableViewColumnsToFit();
updateToolbar();
@ -405,7 +408,8 @@ void GameListWidget::showGameGrid()
return;
}
QtHost::SetBaseBoolSettingValue("UI", "GameListGridView", true);
Host::SetBaseBoolSettingValue("UI", "GameListGridView", true);
Host::CommitBaseSettingChanges();
m_ui.stack->setCurrentIndex(1);
updateToolbar();
emit layoutChange();
@ -416,7 +420,8 @@ void GameListWidget::setShowCoverTitles(bool enabled)
if (m_model->getShowCoverTitles() == enabled)
return;
QtHost::SetBaseBoolSettingValue("UI", "GameListShowCoverTitles", enabled);
Host::SetBaseBoolSettingValue("UI", "GameListShowCoverTitles", enabled);
Host::CommitBaseSettingChanges();
m_model->setShowCoverTitles(enabled);
if (isShowingGameGrid())
m_model->refresh();
@ -508,14 +513,16 @@ void GameListWidget::saveTableViewColumnVisibilitySettings()
for (int column = 0; column < GameListModel::Column_Count; column++)
{
const bool visible = !m_table_view->isColumnHidden(column);
QtHost::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), visible);
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), visible);
Host::CommitBaseSettingChanges();
}
}
void GameListWidget::saveTableViewColumnVisibilitySettings(int column)
{
const bool visible = !m_table_view->isColumnHidden(column);
QtHost::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), visible);
Host::SetBaseBoolSettingValue("GameListTableView", getColumnVisibilitySettingsKeyName(column).c_str(), visible);
Host::CommitBaseSettingChanges();
}
void GameListWidget::loadTableViewColumnSortSettings()
@ -538,11 +545,12 @@ void GameListWidget::saveTableViewColumnSortSettings()
if (sort_column >= 0 && sort_column < GameListModel::Column_Count)
{
QtHost::SetBaseStringSettingValue(
Host::SetBaseStringSettingValue(
"GameListTableView", "SortColumn", GameListModel::getColumnName(static_cast<GameListModel::Column>(sort_column)));
}
QtHost::SetBaseBoolSettingValue("GameListTableView", "SortDescending", sort_descending);
Host::SetBaseBoolSettingValue("GameListTableView", "SortDescending", sort_descending);
Host::CommitBaseSettingChanges();
}
const GameList::Entry* GameListWidget::getSelectedEntry() const

View File

@ -401,6 +401,37 @@ void MainWindow::recreate()
deleteLater();
}
void MainWindow::recreateSettings()
{
QString current_category;
if (m_settings_dialog)
{
current_category = m_settings_dialog->getCategory();
m_settings_dialog->hide();
m_settings_dialog->deleteLater();
m_settings_dialog = nullptr;
}
doSettings(current_category.toUtf8().constData());
}
void MainWindow::resetSettings(bool ui)
{
Host::RequestResetSettings(false, true, false, false, ui);
if (ui)
{
// UI reset includes theme (and eventually language).
// Just updating the theme here, when there's no change, causes Qt to get very confused..
// So, we'll just tear down everything and recreate. We'll need to do that for language
// resets eventaully anyway.
recreate();
}
// g_main_window here for recreate() case above.
g_main_window->recreateSettings();
}
void MainWindow::updateApplicationTheme()
{
if (!s_unthemed_style_name_set)
@ -734,7 +765,8 @@ void MainWindow::onBlockDumpActionToggled(bool checked)
return;
}
QtHost::SetBaseStringSettingValue("EmuCore", "BlockDumpSaveDirectory", new_dir.toUtf8().constData());
Host::SetBaseStringSettingValue("EmuCore", "BlockDumpSaveDirectory", new_dir.toUtf8().constData());
Host::CommitBaseSettingChanges();
}
void MainWindow::saveStateToConfig()
@ -747,7 +779,10 @@ void MainWindow::saveStateToConfig()
const QByteArray geometry_b64 = geometry.toBase64();
const std::string old_geometry_b64 = Host::GetBaseStringSettingValue("UI", "MainWindowGeometry");
if (old_geometry_b64 != geometry_b64.constData())
QtHost::SetBaseStringSettingValue("UI", "MainWindowGeometry", geometry_b64.constData());
{
Host::SetBaseStringSettingValue("UI", "MainWindowGeometry", geometry_b64.constData());
Host::CommitBaseSettingChanges();
}
}
{
@ -755,7 +790,10 @@ void MainWindow::saveStateToConfig()
const QByteArray state_b64 = state.toBase64();
const std::string old_state_b64 = Host::GetBaseStringSettingValue("UI", "MainWindowState");
if (old_state_b64 != state_b64.constData())
QtHost::SetBaseStringSettingValue("UI", "MainWindowState", state_b64.constData());
{
Host::SetBaseStringSettingValue("UI", "MainWindowState", state_b64.constData());
Host::CommitBaseSettingChanges();
}
}
}
@ -1306,19 +1344,22 @@ void MainWindow::onSaveStateMenuAboutToShow()
void MainWindow::onViewToolbarActionToggled(bool checked)
{
QtHost::SetBaseBoolSettingValue("UI", "ShowToolbar", checked);
Host::SetBaseBoolSettingValue("UI", "ShowToolbar", checked);
Host::CommitBaseSettingChanges();
m_ui.toolBar->setVisible(checked);
}
void MainWindow::onViewLockToolbarActionToggled(bool checked)
{
QtHost::SetBaseBoolSettingValue("UI", "LockToolbar", checked);
Host::SetBaseBoolSettingValue("UI", "LockToolbar", checked);
Host::CommitBaseSettingChanges();
m_ui.toolBar->setMovable(!checked);
}
void MainWindow::onViewStatusBarActionToggled(bool checked)
{
QtHost::SetBaseBoolSettingValue("UI", "ShowStatusBar", checked);
Host::SetBaseBoolSettingValue("UI", "ShowStatusBar", checked);
Host::CommitBaseSettingChanges();
m_ui.statusBar->setVisible(checked);
}
@ -1386,7 +1427,8 @@ void MainWindow::onAboutActionTriggered()
void MainWindow::onCheckForUpdatesActionTriggered()
{
// Wipe out the last version, that way it displays the update if we've previously skipped it.
QtHost::RemoveBaseSettingValue("AutoUpdater", "LastVersion");
Host::RemoveBaseSettingValue("AutoUpdater", "LastVersion");
Host::CommitBaseSettingChanges();
checkForUpdates(true);
}
@ -2029,7 +2071,10 @@ void MainWindow::saveDisplayWindowGeometryToConfig()
const QByteArray geometry_b64 = geometry.toBase64();
const std::string old_geometry_b64 = Host::GetBaseStringSettingValue("UI", "DisplayWindowGeometry");
if (old_geometry_b64 != geometry_b64.constData())
QtHost::SetBaseStringSettingValue("UI", "DisplayWindowGeometry", geometry_b64.constData());
{
Host::SetBaseStringSettingValue("UI", "DisplayWindowGeometry", geometry_b64.constData());
Host::CommitBaseSettingChanges();
}
}
void MainWindow::restoreDisplayWindowGeometryFromConfig()

View File

@ -85,6 +85,7 @@ public:
void initialize();
void connectVMThreadSignals(EmuThread* thread);
void startupUpdateCheck();
void resetSettings(bool ui);
/// Locks the VM by pausing it, while a popup dialog is displayed.
VMLock pauseAndLockVM();
@ -167,8 +168,6 @@ private Q_SLOTS:
void onGameChanged(const QString& path, const QString& serial, const QString& name, quint32 crc);
void recreate();
protected:
void showEvent(QShowEvent* event) override;
void closeEvent(QCloseEvent* event) override;
@ -186,6 +185,8 @@ private:
void setupAdditionalUi();
void connectSignals();
void recreate();
void recreateSettings();
void saveStateToConfig();
void restoreStateFromConfig();

View File

@ -24,8 +24,6 @@
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#include <KnownFolders.h>
#include <ShlObj.h>
#endif
#include "common/Assertions.h"
@ -39,6 +37,7 @@
#include "pcsx2/CDVD/CDVDcommon.h"
#include "pcsx2/DebugTools/Debug.h"
#include "pcsx2/Frontend/CommonHost.h"
#include "pcsx2/Frontend/GameList.h"
#include "pcsx2/Frontend/INISettingsInterface.h"
#include "pcsx2/Frontend/LogSink.h"
@ -52,7 +51,6 @@
#include "QtUtils.h"
#include "svnrev.h"
static constexpr u32 SETTINGS_VERSION = 1;
static constexpr u32 SETTINGS_SAVE_DELAY = 1000;
//////////////////////////////////////////////////////////////////////////
@ -64,14 +62,8 @@ static void PrintCommandLineHelp(const char* progname);
static std::shared_ptr<VMBootParameters>& AutoBoot(std::shared_ptr<VMBootParameters>& autoboot);
static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBootParameters>& autoboot);
static bool InitializeConfig();
static bool ShouldUsePortableMode();
static void SetAppRoot();
static void SetResourcesDirectory();
static void SetDataDirectory();
static void HookSignals();
static bool SetCriticalFolders();
static void SetDefaultConfig();
static void SaveSettings();
static void HookSignals();
}
//////////////////////////////////////////////////////////////////////////
@ -89,225 +81,54 @@ static bool s_start_fullscreen_ui_fullscreen = false;
// Initialization/Shutdown
//////////////////////////////////////////////////////////////////////////
bool QtHost::SetCriticalFolders()
{
SetAppRoot();
SetResourcesDirectory();
SetDataDirectory();
// logging of directories in case something goes wrong super early
Console.WriteLn("AppRoot Directory: %s", EmuFolders::AppRoot.c_str());
Console.WriteLn("DataRoot Directory: %s", EmuFolders::DataRoot.c_str());
Console.WriteLn("Resources Directory: %s", EmuFolders::Resources.c_str());
// allow SetDataDirectory() to change settings directory (if we want to split config later on)
if (EmuFolders::Settings.empty())
EmuFolders::Settings = Path::Combine(EmuFolders::DataRoot, "inis");
// Write crash dumps to the data directory, since that'll be accessible for certain.
CrashHandler::SetWriteDirectory(EmuFolders::DataRoot);
// the resources directory should exist, bail out if not
if (!FileSystem::DirectoryExists(EmuFolders::Resources.c_str()))
{
QMessageBox::critical(nullptr, QStringLiteral("Error"),
QStringLiteral("Resources directory is missing, your installation is incomplete."));
return false;
}
return true;
}
bool QtHost::ShouldUsePortableMode()
{
// Check whether portable.ini exists in the program directory.
return FileSystem::FileExists(Path::Combine(EmuFolders::AppRoot, "portable.ini").c_str());
}
void QtHost::SetAppRoot()
{
std::string program_path(FileSystem::GetProgramPath());
Console.WriteLn("Program Path: %s", program_path.c_str());
EmuFolders::AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
}
void QtHost::SetResourcesDirectory()
{
#ifndef __APPLE__
// On Windows/Linux, these are in the binary directory.
EmuFolders::Resources = Path::Combine(EmuFolders::AppRoot, "resources");
#else
// On macOS, this is in the bundle resources directory.
EmuFolders::Resources = Path::Canonicalize(Path::Combine(EmuFolders::AppRoot, "../Resources"));
#endif
}
void QtHost::SetDataDirectory()
{
if (ShouldUsePortableMode())
{
EmuFolders::DataRoot = EmuFolders::AppRoot;
return;
}
#if defined(_WIN32)
// On Windows, use My Documents\PCSX2 to match old installs.
PWSTR documents_directory;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
{
if (std::wcslen(documents_directory) > 0)
EmuFolders::DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2");
CoTaskMemFree(documents_directory);
}
#elif defined(__linux__)
// Use $XDG_CONFIG_HOME/PCSX2 if it exists.
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
{
EmuFolders::DataRoot = Path::Combine(xdg_config_home, "PCSX2");
}
else
{
// Use ~/PCSX2 for non-XDG, and ~/.config/PCSX2 for XDG.
// Maybe we should drop the former when Qt goes live.
const char* home_dir = getenv("HOME");
if (home_dir)
{
#ifndef XDG_STD
EmuFolders::DataRoot = Path::Combine(home_dir, "PCSX2");
#else
// ~/.config should exist, but just in case it doesn't and this is a fresh profile..
const std::string config_dir(Path::Combine(home_dir, ".config"));
if (!FileSystem::DirectoryExists(config_dir.c_str()))
FileSystem::CreateDirectoryPath(config_dir.c_str(), false);
EmuFolders::DataRoot = Path::Combine(config_dir, "PCSX2");
#endif
}
}
#elif defined(__APPLE__)
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2";
const char* home_dir = getenv("HOME");
if (home_dir)
EmuFolders::DataRoot = Path::Combine(home_dir, MAC_DATA_DIR);
#endif
// make sure it exists
if (!EmuFolders::DataRoot.empty() && !FileSystem::DirectoryExists(EmuFolders::DataRoot.c_str()))
{
// we're in trouble if we fail to create this directory... but try to hobble on with portable
if (!FileSystem::CreateDirectoryPath(EmuFolders::DataRoot.c_str(), false))
EmuFolders::DataRoot.clear();
}
// couldn't determine the data directory? fallback to portable.
if (EmuFolders::DataRoot.empty())
EmuFolders::DataRoot = EmuFolders::AppRoot;
}
bool QtHost::InitializeConfig()
{
if (!SetCriticalFolders())
if (!CommonHost::InitializeCriticalFolders())
{
QMessageBox::critical(nullptr, QStringLiteral("PCSX2"),
QStringLiteral("One or more critical directories are missing, your installation may be incomplete."));
return false;
}
const std::string path(Path::Combine(EmuFolders::Settings, "PCSX2.ini"));
Console.WriteLn("Loading config from %s.", path.c_str());
s_base_settings_interface = std::make_unique<INISettingsInterface>(std::move(path));
Host::Internal::SetBaseSettingsLayer(s_base_settings_interface.get());
uint settings_version;
if (!s_base_settings_interface->Load() ||
!s_base_settings_interface->GetUIntValue("UI", "SettingsVersion", &settings_version) ||
settings_version != SETTINGS_VERSION)
if (!s_base_settings_interface->Load() || !CommonHost::CheckSettingsVersion())
{
QMessageBox::critical(
g_main_window, qApp->translate("QtHost", "Settings Reset"),
qApp->translate("QtHost", "Settings do not exist or are the incorrect version, resetting to defaults."));
SetDefaultConfig();
s_base_settings_interface->Save();
// If the config file doesn't exist, assume this is a new install and don't prompt to overwrite.
if (FileSystem::FileExists(s_base_settings_interface->GetFileName().c_str()) &&
QMessageBox::question(nullptr, QStringLiteral("PCSX2"),
QStringLiteral("Settings failed to load, or are the incorrect version. Clicking Yes will reset all settings to defaults. Do you want to continue?")) != QMessageBox::Yes)
{
return false;
}
CommonHost::SetDefaultSettings(*s_base_settings_interface, true, true, true, true, true);
SaveSettings();
}
// TODO: Handle reset to defaults if load fails.
EmuFolders::LoadConfig(*s_base_settings_interface.get());
EmuFolders::EnsureFoldersExist();
CommonHost::LoadStartupSettings();
Host::UpdateLogging(QtHost::InNoGUIMode());
return true;
}
void QtHost::SetDefaultConfig()
void Host::SetDefaultUISettings(SettingsInterface& si)
{
EmuFolders::SetDefaults();
EmuFolders::EnsureFoldersExist();
Host::SetDefaultLoggingSettings(si);
SettingsInterface& si = *s_base_settings_interface.get();
si.SetUIntValue("UI", "SettingsVersion", SETTINGS_VERSION);
VMManager::SetDefaultSettings(si);
EmuFolders::Save(si);
PAD::SetDefaultControllerConfig(si);
PAD::SetDefaultHotkeyConfig(si);
}
void QtHost::SetBaseBoolSettingValue(const char* section, const char* key, bool value)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetBoolValue(section, key, value);
QueueSettingsSave();
}
void QtHost::SetBaseIntSettingValue(const char* section, const char* key, int value)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetIntValue(section, key, value);
QueueSettingsSave();
}
void QtHost::SetBaseFloatSettingValue(const char* section, const char* key, float value)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetFloatValue(section, key, value);
QueueSettingsSave();
}
void QtHost::SetBaseStringSettingValue(const char* section, const char* key, const char* value)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetStringValue(section, key, value);
QueueSettingsSave();
}
void QtHost::SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->SetStringList(section, key, values);
QueueSettingsSave();
}
bool QtHost::AddBaseValueToStringList(const char* section, const char* key, const char* value)
{
auto lock = Host::GetSettingsLock();
if (!s_base_settings_interface->AddToStringList(section, key, value))
return false;
QueueSettingsSave();
return true;
}
bool QtHost::RemoveBaseValueFromStringList(const char* section, const char* key, const char* value)
{
auto lock = Host::GetSettingsLock();
if (!s_base_settings_interface->RemoveFromStringList(section, key, value))
return false;
QueueSettingsSave();
return true;
}
void QtHost::RemoveBaseSettingValue(const char* section, const char* key)
{
auto lock = Host::GetSettingsLock();
s_base_settings_interface->DeleteValue(section, key);
QueueSettingsSave();
si.SetBoolValue("UI", "InhibitScreensaver", true);
si.SetBoolValue("UI", "ConfirmShutdown", true);
si.SetBoolValue("UI", "StartPaused", false);
si.SetBoolValue("UI", "PauseOnFocusLoss", false);
si.SetBoolValue("UI", "StartFullscreen", false);
si.SetBoolValue("UI", "DoubleClickTogglesFullscreen", true);
si.SetBoolValue("UI", "HideMouseCursor", false);
si.SetBoolValue("UI", "RenderToSeparateWindow", false);
si.SetBoolValue("UI", "HideMainWindowWhenRunning", false);
si.SetBoolValue("UI", "DisableWindowResize", false);
si.SetStringValue("UI", "Theme", MainWindow::DEFAULT_THEME_NAME);
}
void QtHost::SaveSettings()
@ -324,13 +145,20 @@ void QtHost::SaveSettings()
s_settings_save_timer.release();
}
void QtHost::QueueSettingsSave()
void Host::CommitBaseSettingChanges()
{
if (!QtHost::IsOnUIThread())
{
QtHost::RunOnUIThread(&Host::CommitBaseSettingChanges);
return;
}
auto lock = Host::GetSettingsLock();
if (s_settings_save_timer)
return;
s_settings_save_timer = std::make_unique<QTimer>();
s_settings_save_timer->connect(s_settings_save_timer.get(), &QTimer::timeout, SaveSettings);
s_settings_save_timer->connect(s_settings_save_timer.get(), &QTimer::timeout, &QtHost::SaveSettings);
s_settings_save_timer->setSingleShot(true);
s_settings_save_timer->start(SETTINGS_SAVE_DELAY);
}
@ -345,6 +173,12 @@ bool QtHost::InNoGUIMode()
return s_nogui_mode;
}
bool QtHost::IsOnUIThread()
{
QThread* ui_thread = qApp->thread();
return (QThread::currentThread() == ui_thread);
}
void QtHost::RunOnUIThread(const std::function<void()>& func, bool block /*= false*/)
{
// main window always exists, so it's fine to attach it to that.
@ -353,6 +187,21 @@ void QtHost::RunOnUIThread(const std::function<void()>& func, bool block /*= fal
Q_ARG(const std::function<void()>&, func));
}
bool Host::RequestResetSettings(bool folders, bool core, bool controllers, bool hotkeys, bool ui)
{
{
auto lock = Host::GetSettingsLock();
CommonHost::SetDefaultSettings(*s_base_settings_interface.get(), folders, core, controllers, hotkeys, ui);
}
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
if (folders)
g_emu_thread->updateEmuFolders();
return true;
}
QString QtHost::GetAppNameAndVersion()
{
QString ret;
@ -725,11 +574,7 @@ int main(int argc, char* argv[])
// Bail out if we can't find any config.
if (!QtHost::InitializeConfig())
{
// NOTE: No point translating this, because no config means the language won't be loaded anyway.
QMessageBox::critical(nullptr, QStringLiteral("Error"), QStringLiteral("Failed to initialize config."));
return EXIT_FAILURE;
}
// Set theme before creating any windows.
MainWindow::updateApplicationTheme();

View File

@ -46,6 +46,9 @@ namespace QtHost
/// Sets NoGUI mode (implys batch mode, does not display main window, exits on shutdown).
bool InNoGUIMode();
/// Returns true if the calling thread is the UI thread.
bool IsOnUIThread();
/// Executes a function on the UI thread.
void RunOnUIThread(const std::function<void()>& func, bool block = false);
@ -58,17 +61,6 @@ namespace QtHost
/// Returns the base path for resources. This may be : prefixed, if we're using embedded resources.
QString GetResourcesBasePath();
/// Thread-safe settings access.
void SetBaseBoolSettingValue(const char* section, const char* key, bool value);
void SetBaseIntSettingValue(const char* section, const char* key, int value);
void SetBaseFloatSettingValue(const char* section, const char* key, float value);
void SetBaseStringSettingValue(const char* section, const char* key, const char* value);
void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
bool AddBaseValueToStringList(const char* section, const char* key, const char* value);
bool RemoveBaseValueFromStringList(const char* section, const char* key, const char* value);
void RemoveBaseSettingValue(const char* section, const char* key);
void QueueSettingsSave();
/// VM state, safe to access on UI thread.
bool IsVMValid();
bool IsVMPaused();

View File

@ -613,7 +613,8 @@ namespace SettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
const bool new_value = Accessor::getBoolValue(widget);
QtHost::SetBaseBoolSettingValue(section.c_str(), key.c_str(), new_value);
Host::SetBaseBoolSettingValue(section.c_str(), key.c_str(), new_value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -653,7 +654,8 @@ namespace SettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), option_offset]() {
const int new_value = Accessor::getIntValue(widget);
QtHost::SetBaseIntSettingValue(section.c_str(), key.c_str(), new_value + option_offset);
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), new_value + option_offset);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -692,7 +694,8 @@ namespace SettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
const float new_value = Accessor::getFloatValue(widget);
QtHost::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -732,7 +735,8 @@ namespace SettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), range]() {
const float new_value = (static_cast<float>(Accessor::getIntValue(widget)) / range);
QtHost::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -773,10 +777,11 @@ namespace SettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
const QString new_value = Accessor::getStringValue(widget);
if (!new_value.isEmpty())
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), new_value.toUtf8().constData());
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), new_value.toUtf8().constData());
else
QtHost::RemoveBaseSettingValue(section.c_str(), key.c_str());
Host::RemoveBaseSettingValue(section.c_str(), key.c_str());
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -835,7 +840,8 @@ namespace SettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), to_string_function]() {
const DataType value = static_cast<DataType>(static_cast<UnderlyingType>(Accessor::getIntValue(widget)));
const char* string_value = to_string_function(value);
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), string_value);
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), string_value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -896,7 +902,8 @@ namespace SettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), enum_names]() {
const UnderlyingType value = static_cast<UnderlyingType>(Accessor::getIntValue(widget));
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), enum_names[value]);
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), enum_names[value]);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -959,7 +966,8 @@ namespace SettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), enum_values]() {
const int value = Accessor::getIntValue(widget);
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), enum_values[value]);
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), enum_values[value]);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -996,13 +1004,14 @@ namespace SettingWidgetBinder
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());
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), relative_path.c_str());
}
else
{
QtHost::RemoveBaseSettingValue(section.c_str(), key.c_str());
Host::RemoveBaseSettingValue(section.c_str(), key.c_str());
}
Host::CommitBaseSettingChanges();
g_emu_thread->updateEmuFolders();
});

View File

@ -130,7 +130,8 @@ void BIOSSettingsWidget::listRefreshed(const QVector<BIOSInfo>& items)
void BIOSSettingsWidget::listItemChanged(const QTreeWidgetItem* current, const QTreeWidgetItem* previous)
{
QtHost::SetBaseStringSettingValue("Filenames", "BIOS", current->text(0).toUtf8().constData());
Host::SetBaseStringSettingValue("Filenames", "BIOS", current->text(0).toUtf8().constData());
Host::CommitBaseSettingChanges();
}
BIOSSettingsWidget::RefreshThread::RefreshThread(BIOSSettingsWidget* parent, const QString& directory)

View File

@ -199,13 +199,17 @@ void ControllerBindingWidget::onClearBindingsClicked()
{
auto lock = Host::GetSettingsLock();
PAD::ClearPortBindings(*Host::Internal::GetBaseSettingsLayer(), m_port_number);
Host::CommitBaseSettingChanges();
}
else
{
PAD::ClearPortBindings(*m_dialog->getProfileSettingsInterface(), m_port_number);
m_dialog->getProfileSettingsInterface()->Save();
}
saveAndRefresh();
// force a refresh after clearing
g_emu_thread->applySettings();
onTypeChanged();
}
void ControllerBindingWidget::doDeviceAutomaticBinding(const QString& device)
@ -223,27 +227,27 @@ void ControllerBindingWidget::doDeviceAutomaticBinding(const QString& device)
{
auto lock = Host::GetSettingsLock();
result = PAD::MapController(*Host::Internal::GetBaseSettingsLayer(), m_port_number, mapping);
if (result)
Host::CommitBaseSettingChanges();
}
else
{
result = PAD::MapController(*m_dialog->getProfileSettingsInterface(), m_port_number, mapping);
m_dialog->getProfileSettingsInterface()->Save();
g_emu_thread->reloadInputBindings();
if (result)
{
m_dialog->getProfileSettingsInterface()->Save();
g_emu_thread->reloadInputBindings();
}
}
// force a refresh after mapping
if (result)
saveAndRefresh();
{
g_emu_thread->applySettings();
onTypeChanged();
}
}
void ControllerBindingWidget::saveAndRefresh()
{
onTypeChanged();
QtHost::QueueSettingsSave();
g_emu_thread->applySettings();
}
//////////////////////////////////////////////////////////////////////////
ControllerMacroWidget::ControllerMacroWidget(ControllerBindingWidget* parent)

View File

@ -58,7 +58,6 @@ private:
void populateControllerTypes();
void updateHeaderToolButtons();
void doDeviceAutomaticBinding(const QString& device);
void saveAndRefresh();
Ui::ControllerBindingWidget m_ui;

View File

@ -63,7 +63,8 @@ namespace ControllerSettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
const bool new_value = Accessor::getBoolValue(widget);
QtHost::SetBaseBoolSettingValue(section.c_str(), key.c_str(), new_value);
Host::SetBaseBoolSettingValue(section.c_str(), key.c_str(), new_value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -94,7 +95,8 @@ namespace ControllerSettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
const float new_value = Accessor::getFloatValue(widget);
QtHost::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -127,7 +129,8 @@ namespace ControllerSettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), range]() {
const float new_value = (static_cast<float>(Accessor::getIntValue(widget)) / range);
QtHost::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
@ -166,10 +169,11 @@ namespace ControllerSettingWidgetBinder
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
const QString new_value = Accessor::getStringValue(widget);
if (!new_value.isEmpty())
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), new_value.toUtf8().constData());
Host::SetBaseStringSettingValue(section.c_str(), key.c_str(), new_value.toUtf8().constData());
else
QtHost::RemoveBaseSettingValue(section.c_str(), key.c_str());
Host::RemoveBaseSettingValue(section.c_str(), key.c_str());
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}

View File

@ -22,6 +22,7 @@
#include "Settings/ControllerBindingWidgets.h"
#include "Settings/HotkeySettingsWidget.h"
#include "pcsx2/Frontend/CommonHost.h"
#include "pcsx2/Frontend/INISettingsInterface.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/Sio.h"
@ -162,7 +163,7 @@ void ControllerSettingsDialog::onLoadProfileClicked()
{
auto lock = Host::GetSettingsLock();
PAD::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_profile_interface, true, true, false);
QtHost::QueueSettingsSave();
Host::CommitBaseSettingChanges();
}
g_emu_thread->applySettings();
@ -206,9 +207,8 @@ void ControllerSettingsDialog::onRestoreDefaultsClicked()
// actually restore it
{
auto lock = Host::GetSettingsLock();
PAD::SetDefaultControllerConfig(*Host::Internal::GetBaseSettingsLayer());
PAD::SetDefaultHotkeyConfig(*Host::Internal::GetBaseSettingsLayer());
QtHost::QueueSettingsSave();
CommonHost::SetDefaultSettings(*Host::Internal::GetBaseSettingsLayer(), false, false, true, true, false);
Host::CommitBaseSettingChanges();
}
g_emu_thread->applySettings();
@ -295,7 +295,8 @@ void ControllerSettingsDialog::setBoolValue(const char* section, const char* key
}
else
{
QtHost::SetBaseBoolSettingValue(section, key, value);
Host::SetBaseBoolSettingValue(section, key, value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
}
}
@ -310,7 +311,8 @@ void ControllerSettingsDialog::setIntValue(const char* section, const char* key,
}
else
{
QtHost::SetBaseIntSettingValue(section, key, value);
Host::SetBaseIntSettingValue(section, key, value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
}
}
@ -325,7 +327,8 @@ void ControllerSettingsDialog::setStringValue(const char* section, const char* k
}
else
{
QtHost::SetBaseStringSettingValue(section, key, value);
Host::SetBaseStringSettingValue(section, key, value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
}
}
@ -340,7 +343,8 @@ void ControllerSettingsDialog::clearSettingValue(const char* section, const char
}
else
{
QtHost::RemoveBaseSettingValue(section, key);
Host::RemoveBaseSettingValue(section, key);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
}
}

View File

@ -65,9 +65,10 @@ GameListSettingsWidget::~GameListSettingsWidget() = default;
bool GameListSettingsWidget::addExcludedPath(const std::string& path)
{
if (!QtHost::AddBaseValueToStringList("GameList", "ExcludedPaths", path.c_str()))
if (!Host::AddBaseValueToStringList("GameList", "ExcludedPaths", path.c_str()))
return false;
Host::CommitBaseSettingChanges();
m_ui.excludedPaths->addItem(QString::fromStdString(path));
g_main_window->refreshGameList(false);
return true;
@ -107,14 +108,15 @@ void GameListSettingsWidget::addPathToTable(const std::string& path, bool recurs
const std::string path(item->text().toStdString());
if (state == Qt::Checked)
{
QtHost::RemoveBaseValueFromStringList("GameList", "Paths", path.c_str());
QtHost::AddBaseValueToStringList("GameList", "RecursivePaths", path.c_str());
Host::RemoveBaseValueFromStringList("GameList", "Paths", path.c_str());
Host::AddBaseValueToStringList("GameList", "RecursivePaths", path.c_str());
}
else
{
QtHost::RemoveBaseValueFromStringList("GameList", "RecursivePaths", path.c_str());
QtHost::AddBaseValueToStringList("GameList", "Paths", path.c_str());
Host::RemoveBaseValueFromStringList("GameList", "RecursivePaths", path.c_str());
Host::AddBaseValueToStringList("GameList", "Paths", path.c_str());
}
Host::CommitBaseSettingChanges();
});
}
@ -138,8 +140,9 @@ void GameListSettingsWidget::refreshDirectoryList()
void GameListSettingsWidget::addSearchDirectory(const QString& path, bool recursive)
{
const std::string spath(path.toStdString());
QtHost::RemoveBaseValueFromStringList("GameList", recursive ? "Paths" : "RecursivePaths", spath.c_str());
QtHost::AddBaseValueToStringList("GameList", recursive ? "RecursivePaths" : "Paths", spath.c_str());
Host::RemoveBaseValueFromStringList("GameList", recursive ? "Paths" : "RecursivePaths", spath.c_str());
Host::AddBaseValueToStringList("GameList", recursive ? "RecursivePaths" : "Paths", spath.c_str());
Host::CommitBaseSettingChanges();
refreshDirectoryList();
g_main_window->refreshGameList(false);
}
@ -147,12 +150,13 @@ void GameListSettingsWidget::addSearchDirectory(const QString& path, bool recurs
void GameListSettingsWidget::removeSearchDirectory(const QString& path)
{
const std::string spath(path.toStdString());
if (!QtHost::RemoveBaseValueFromStringList("GameList", "Paths", spath.c_str()) &&
!QtHost::RemoveBaseValueFromStringList("GameList", "RecursivePaths", spath.c_str()))
if (!Host::RemoveBaseValueFromStringList("GameList", "Paths", spath.c_str()) &&
!Host::RemoveBaseValueFromStringList("GameList", "RecursivePaths", spath.c_str()))
{
return;
}
Host::CommitBaseSettingChanges();
refreshDirectoryList();
g_main_window->refreshGameList(false);
}
@ -228,7 +232,9 @@ void GameListSettingsWidget::onRemoveExcludedPathButtonClicked()
if (!item)
return;
QtHost::RemoveBaseValueFromStringList("GameList", "ExcludedPaths", item->text().toUtf8().constData());
if (Host::RemoveBaseValueFromStringList("GameList", "ExcludedPaths", item->text().toUtf8().constData()))
Host::CommitBaseSettingChanges();
delete item;
g_main_window->refreshGameList(false);

View File

@ -259,9 +259,10 @@ void InputBindingDialog::saveListToSettings()
else
{
if (!m_bindings.empty())
QtHost::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
Host::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
else
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
Host::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
Host::CommitBaseSettingChanges();
g_emu_thread->reloadInputBindings();
}
}

View File

@ -236,7 +236,8 @@ void InputBindingWidget::setNewBinding()
}
else
{
QtHost::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), new_binding.c_str());
Host::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), new_binding.c_str());
Host::CommitBaseSettingChanges();
g_emu_thread->reloadInputBindings();
}
}
@ -256,7 +257,8 @@ void InputBindingWidget::clearBinding()
}
else
{
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
Host::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
Host::CommitBaseSettingChanges();
g_emu_thread->reloadInputBindings();
}
reloadBinding();
@ -413,7 +415,8 @@ void InputVibrationBindingWidget::setKey(ControllerSettingsDialog* dialog, std::
void InputVibrationBindingWidget::clearBinding()
{
m_binding = {};
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
Host::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
Host::CommitBaseSettingChanges();
g_emu_thread->reloadInputBindings();
setText(QString());
}
@ -448,7 +451,8 @@ void InputVibrationBindingWidget::onClicked()
const QString new_value(input_dialog.textValue());
m_binding = new_value.toStdString();
QtHost::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_binding.c_str());
Host::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_binding.c_str());
Host::CommitBaseSettingChanges();
setText(new_value);
}

View File

@ -146,9 +146,6 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &SettingsDialog::onCategoryCurrentRowChanged);
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::accept);
connect(m_ui.restoreDefaultsButton, &QPushButton::clicked, this, &SettingsDialog::onRestoreDefaultsClicked);
// TODO: Remove this once they're implemented.
m_ui.restoreDefaultsButton->setVisible(false);
}
SettingsDialog::~SettingsDialog()
@ -164,6 +161,11 @@ void SettingsDialog::closeEvent(QCloseEvent*)
deleteLater();
}
QString SettingsDialog::getCategory() const
{
return m_ui.settingsCategory->item(m_ui.settingsCategory->currentRow())->text();
}
void SettingsDialog::setCategory(const char* category)
{
// the titles in the category list will be translated.
@ -188,14 +190,20 @@ void SettingsDialog::onCategoryCurrentRowChanged(int row)
void SettingsDialog::onRestoreDefaultsClicked()
{
if (QMessageBox::question(this, tr("Confirm Restore Defaults"),
tr("Are you sure you want to restore the default settings? Any preferences will be lost."), QMessageBox::Yes,
QMessageBox::No) != QMessageBox::Yes)
{
return;
}
QMessageBox msgbox(this);
msgbox.setIcon(QMessageBox::Question);
msgbox.setWindowTitle(tr("Confirm Restore Defaults"));
msgbox.setText(tr("Are you sure you want to restore the default settings? Any preferences will be lost."));
// TODO
QCheckBox* ui_cb = new QCheckBox(tr("Reset UI Settings"), &msgbox);
msgbox.setCheckBox(ui_cb);
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::Yes);
if (msgbox.exec() != QMessageBox::Yes)
return;
g_main_window->resetSettings(ui_cb->isChecked());
}
void SettingsDialog::addWidget(QWidget* widget, QString title, QString icon, QString help_text)
@ -376,7 +384,8 @@ void SettingsDialog::setBoolSettingValue(const char* section, const char* key, s
}
else
{
value.has_value() ? QtHost::SetBaseBoolSettingValue(section, key, value.value()) : QtHost::RemoveBaseSettingValue(section, key);
value.has_value() ? Host::SetBaseBoolSettingValue(section, key, value.value()) : Host::RemoveBaseSettingValue(section, key);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
}
}
@ -391,7 +400,8 @@ void SettingsDialog::setIntSettingValue(const char* section, const char* key, st
}
else
{
value.has_value() ? QtHost::SetBaseIntSettingValue(section, key, value.value()) : QtHost::RemoveBaseSettingValue(section, key);
value.has_value() ? Host::SetBaseIntSettingValue(section, key, value.value()) : Host::RemoveBaseSettingValue(section, key);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
}
}
@ -406,7 +416,8 @@ void SettingsDialog::setFloatSettingValue(const char* section, const char* key,
}
else
{
value.has_value() ? QtHost::SetBaseFloatSettingValue(section, key, value.value()) : QtHost::RemoveBaseSettingValue(section, key);
value.has_value() ? Host::SetBaseFloatSettingValue(section, key, value.value()) : Host::RemoveBaseSettingValue(section, key);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
}
}
@ -421,7 +432,8 @@ void SettingsDialog::setStringSettingValue(const char* section, const char* key,
}
else
{
value.has_value() ? QtHost::SetBaseStringSettingValue(section, key, value.value()) : QtHost::RemoveBaseSettingValue(section, key);
value.has_value() ? Host::SetBaseStringSettingValue(section, key, value.value()) : Host::RemoveBaseSettingValue(section, key);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
}
}

View File

@ -72,6 +72,7 @@ public:
void registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text);
bool eventFilter(QObject* object, QEvent* event) override;
QString getCategory() const;
void setCategory(const char* category);
// Helper functions for reading effective setting values (from game -> global settings).

View File

@ -1063,8 +1063,10 @@ endif()
if(PCSX2_CORE)
list(APPEND pcsx2FrontendSources
Frontend/CommonHost.cpp
Frontend/FullscreenUI.cpp
Frontend/GameList.cpp
Frontend/HostSettings.cpp
Frontend/ImGuiFullscreen.cpp
Frontend/INISettingsInterface.cpp
Frontend/InputManager.cpp
@ -1072,10 +1074,10 @@ if(PCSX2_CORE)
Frontend/LayeredSettingsInterface.cpp
Frontend/LogSink.cpp
GSDumpReplayer.cpp
HostSettings.cpp
VMManager.cpp
)
list(APPEND pcsx2FrontendHeaders
Frontend/CommonHost.h
Frontend/FullscreenUI.h
Frontend/GameList.h
Frontend/ImGuiFullscreen.h

View File

@ -1048,10 +1048,9 @@ namespace EmuFolders
extern std::string InputProfiles;
// Assumes that AppRoot and DataRoot have been initialized.
void SetDefaults();
bool EnsureFoldersExist();
void SetDefaults(SettingsInterface& si);
void LoadConfig(SettingsInterface& si);
void Save(SettingsInterface& si);
bool EnsureFoldersExist();
} // namespace EmuFolders
/////////////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,203 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "common/Assertions.h"
#include "common/CrashHandler.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "Frontend/CommonHost.h"
#include "Frontend/LayeredSettingsInterface.h"
#include "GS.h"
#include "GS/Renderers/HW/GSTextureReplacements.h"
#include "Host.h"
#include "HostSettings.h"
#include "MemoryCardFile.h"
#include "PAD/Host/PAD.h"
#include "Sio.h"
#include "VMManager.h"
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#include <KnownFolders.h>
#include <ShlObj.h>
#endif
static constexpr u32 SETTINGS_VERSION = 1;
namespace CommonHost
{
static void SetAppRoot();
static void SetResourcesDirectory();
static bool ShouldUsePortableMode();
static void SetDataDirectory();
static void SetCommonDefaultSettings(SettingsInterface& si);
} // namespace CommonHost
bool CommonHost::InitializeCriticalFolders()
{
SetAppRoot();
SetResourcesDirectory();
SetDataDirectory();
// logging of directories in case something goes wrong super early
Console.WriteLn("AppRoot Directory: %s", EmuFolders::AppRoot.c_str());
Console.WriteLn("DataRoot Directory: %s", EmuFolders::DataRoot.c_str());
Console.WriteLn("Resources Directory: %s", EmuFolders::Resources.c_str());
// allow SetDataDirectory() to change settings directory (if we want to split config later on)
if (EmuFolders::Settings.empty())
EmuFolders::Settings = Path::Combine(EmuFolders::DataRoot, "inis");
// Write crash dumps to the data directory, since that'll be accessible for certain.
CrashHandler::SetWriteDirectory(EmuFolders::DataRoot);
// the resources directory should exist, bail out if not
if (!FileSystem::DirectoryExists(EmuFolders::Resources.c_str()))
{
Console.Error("Resources directory is missing.");
return false;
}
return true;
}
void CommonHost::SetAppRoot()
{
std::string program_path(FileSystem::GetProgramPath());
Console.WriteLn("Program Path: %s", program_path.c_str());
EmuFolders::AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
}
void CommonHost::SetResourcesDirectory()
{
#ifndef __APPLE__
// On Windows/Linux, these are in the binary directory.
EmuFolders::Resources = Path::Combine(EmuFolders::AppRoot, "resources");
#else
// On macOS, this is in the bundle resources directory.
EmuFolders::Resources = Path::Canonicalize(Path::Combine(EmuFolders::AppRoot, "../Resources"));
#endif
}
bool CommonHost::ShouldUsePortableMode()
{
// Check whether portable.ini exists in the program directory.
return FileSystem::FileExists(Path::Combine(EmuFolders::AppRoot, "portable.ini").c_str());
}
void CommonHost::SetDataDirectory()
{
if (ShouldUsePortableMode())
{
EmuFolders::DataRoot = EmuFolders::AppRoot;
return;
}
#if defined(_WIN32)
// On Windows, use My Documents\PCSX2 to match old installs.
PWSTR documents_directory;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
{
if (std::wcslen(documents_directory) > 0)
EmuFolders::DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2");
CoTaskMemFree(documents_directory);
}
#elif defined(__linux__)
// Use $XDG_CONFIG_HOME/PCSX2 if it exists.
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
{
EmuFolders::DataRoot = Path::Combine(xdg_config_home, "PCSX2");
}
else
{
// Use ~/PCSX2 for non-XDG, and ~/.config/PCSX2 for XDG.
// Maybe we should drop the former when Qt goes live.
const char* home_dir = getenv("HOME");
if (home_dir)
{
#ifndef XDG_STD
EmuFolders::DataRoot = Path::Combine(home_dir, "PCSX2");
#else
// ~/.config should exist, but just in case it doesn't and this is a fresh profile..
const std::string config_dir(Path::Combine(home_dir, ".config"));
if (!FileSystem::DirectoryExists(config_dir.c_str()))
FileSystem::CreateDirectoryPath(config_dir.c_str(), false);
EmuFolders::DataRoot = Path::Combine(config_dir, "PCSX2");
#endif
}
}
#elif defined(__APPLE__)
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2";
const char* home_dir = getenv("HOME");
if (home_dir)
EmuFolders::DataRoot = Path::Combine(home_dir, MAC_DATA_DIR);
#endif
// make sure it exists
if (!EmuFolders::DataRoot.empty() && !FileSystem::DirectoryExists(EmuFolders::DataRoot.c_str()))
{
// we're in trouble if we fail to create this directory... but try to hobble on with portable
if (!FileSystem::CreateDirectoryPath(EmuFolders::DataRoot.c_str(), false))
EmuFolders::DataRoot.clear();
}
// couldn't determine the data directory? fallback to portable.
if (EmuFolders::DataRoot.empty())
EmuFolders::DataRoot = EmuFolders::AppRoot;
}
bool CommonHost::CheckSettingsVersion()
{
SettingsInterface* bsi = Host::Internal::GetBaseSettingsLayer();
uint settings_version;
return (bsi->GetUIntValue("UI", "SettingsVersion", &settings_version) && settings_version == SETTINGS_VERSION);
}
void CommonHost::LoadStartupSettings()
{
SettingsInterface* bsi = Host::Internal::GetBaseSettingsLayer();
EmuFolders::LoadConfig(*bsi);
EmuFolders::EnsureFoldersExist();
}
void CommonHost::SetDefaultSettings(SettingsInterface& si, bool folders, bool core, bool controllers, bool hotkeys, bool ui)
{
if (si.GetUIntValue("UI", "SettingsVersion", 0u) != SETTINGS_VERSION)
si.SetUIntValue("UI", "SettingsVersion", SETTINGS_VERSION);
if (folders)
EmuFolders::SetDefaults(si);
if (core)
{
VMManager::SetDefaultSettings(si);
SetCommonDefaultSettings(si);
}
if (controllers)
PAD::SetDefaultControllerConfig(si);
if (hotkeys)
PAD::SetDefaultHotkeyConfig(si);
if (ui)
Host::SetDefaultUISettings(si);
}
void CommonHost::SetCommonDefaultSettings(SettingsInterface& si)
{
// Nothing here yet.
}

View File

@ -0,0 +1,43 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include <string>
#include <mutex>
class SettingsInterface;
namespace Host
{
/// Sets host-specific default settings.
void SetDefaultUISettings(SettingsInterface& si);
} // namespace Host
namespace CommonHost
{
/// Initializes critical folders (AppRoot, DataRoot, Settings). Call once on startup.
bool InitializeCriticalFolders();
/// Checks settings version. Call once on startup. If it returns false, you should prompt the user to reset.
bool CheckSettingsVersion();
/// Loads early settings. Call once on startup.
void LoadStartupSettings();
/// Sets default settings for the specified categories.
void SetDefaultSettings(SettingsInterface& si, bool folders, bool core, bool controllers, bool hotkeys, bool ui);
} // namespace CommonHost

View File

@ -119,7 +119,9 @@ using ImGuiFullscreen::MenuImageButton;
using ImGuiFullscreen::NavButton;
using ImGuiFullscreen::NavTitle;
using ImGuiFullscreen::OpenChoiceDialog;
using ImGuiFullscreen::OpenConfirmMessageDialog;
using ImGuiFullscreen::OpenFileSelector;
using ImGuiFullscreen::OpenInfoMessageDialog;
using ImGuiFullscreen::OpenInputStringDialog;
using ImGuiFullscreen::PopPrimaryColor;
using ImGuiFullscreen::PushPrimaryColor;
@ -279,6 +281,7 @@ namespace FullscreenUI
static void DoLoadInputProfile();
static void DoSaveInputProfile();
static void DoSaveInputProfile(const std::string& name);
static void DoResetSettings();
static bool DrawToggleSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key,
bool default_value, bool enabled = true, bool allow_tristate = true, float height = ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT,
@ -2022,6 +2025,13 @@ void FullscreenUI::DrawInterfaceSettingsPage()
DrawToggleSetting(bsi, ICON_FA_PLAY " Show Status Indicators",
"Shows indicators when fast forwarding, pausing, and other abnormal states are active.", "EmuCore/GS", "OsdShowIndicators", true);
MenuHeading("Operations");
if (MenuButton(ICON_FA_FOLDER_MINUS " Reset Settings", "Resets configuration to defaults (excluding controller settings).",
!IsEditingGameSettings(bsi)))
{
DoResetSettings();
}
EndMenuButtons();
}
@ -3006,6 +3016,18 @@ void FullscreenUI::DoSaveInputProfile()
});
}
void FullscreenUI::DoResetSettings()
{
OpenConfirmMessageDialog(ICON_FA_FOLDER_MINUS " Reset Settings",
"Are you sure you want to restore the default settings? Any preferences will be lost.", [](bool result) {
if (result)
{
Host::RunOnCPUThread([]() { Host::RequestResetSettings(false, true, false, false, false); });
ShowToast(std::string(), "Settings reset to defaults.");
}
});
}
void FullscreenUI::DrawControllerSettingsPage()
{
BeginMenuButtons();
@ -4177,98 +4199,6 @@ void FullscreenUI::DrawAboutWindow()
ImGui::PopFont();
}
bool FullscreenUI::DrawErrorWindow(const char* message)
{
bool is_open = true;
ImGuiFullscreen::BeginLayout();
ImGui::SetNextWindowSize(LayoutScale(500.0f, 0.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup("ReportError");
ImGui::PushFont(g_large_font);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(10.0f, 10.0f));
if (ImGui::BeginPopupModal("ReportError", &is_open, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize))
{
ImGui::SetCursorPos(LayoutScale(LAYOUT_MENU_BUTTON_X_PADDING, LAYOUT_MENU_BUTTON_Y_PADDING));
ImGui::TextWrapped("%s", message);
ImGui::GetCurrentWindow()->DC.CursorPos.y += LayoutScale(5.0f);
BeginMenuButtons();
if (ActiveButton(ICON_FA_WINDOW_CLOSE " Close", false))
{
ImGui::CloseCurrentPopup();
is_open = false;
}
EndMenuButtons();
ImGui::EndPopup();
}
ImGui::PopStyleVar(2);
ImGui::PopFont();
ImGuiFullscreen::EndLayout();
return !is_open;
}
bool FullscreenUI::DrawConfirmWindow(const char* message, bool* result)
{
bool is_open = true;
ImGuiFullscreen::BeginLayout();
ImGui::SetNextWindowSize(LayoutScale(500.0f, 0.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup("ConfirmMessage");
ImGui::PushFont(g_large_font);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(10.0f, 10.0f));
if (ImGui::BeginPopupModal("ConfirmMessage", &is_open, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize))
{
ImGui::SetCursorPos(LayoutScale(LAYOUT_MENU_BUTTON_X_PADDING, LAYOUT_MENU_BUTTON_Y_PADDING));
ImGui::TextWrapped("%s", message);
ImGui::GetCurrentWindow()->DC.CursorPos.y += LayoutScale(5.0f);
BeginMenuButtons();
bool done = false;
if (ActiveButton(ICON_FA_CHECK " Yes", false))
{
*result = true;
done = true;
}
if (ActiveButton(ICON_FA_TIMES " No", false))
{
*result = false;
done = true;
}
if (done)
{
ImGui::CloseCurrentPopup();
is_open = false;
}
EndMenuButtons();
ImGui::EndPopup();
}
ImGui::PopStyleVar(2);
ImGui::PopFont();
ImGuiFullscreen::EndLayout();
return !is_open;
}
FullscreenUI::ProgressCallback::ProgressCallback(std::string name)
: BaseProgressCallback()
, m_name(std::move(name))

View File

@ -36,10 +36,6 @@ namespace FullscreenUI
void Shutdown();
void Render();
// Returns true if the message has been dismissed.
bool DrawErrorWindow(const char* message);
bool DrawConfirmWindow(const char* message, bool* result);
class ProgressCallback final : public BaseProgressCallback
{
public:

View File

@ -15,6 +15,9 @@
#include "PrecompiledHeader.h"
#include "common/Assertions.h"
#include "common/CrashHandler.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "Frontend/LayeredSettingsInterface.h"
#include "GS.h"
#include "GS/Renderers/HW/GSTextureReplacements.h"
@ -121,18 +124,24 @@ void Host::SetBaseStringListSettingValue(const char* section, const char* key, c
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->SetStringList(section, key, values);
}
void Host::DeleteBaseSettingValue(const char* section, const char* key)
bool Host::AddBaseValueToStringList(const char* section, const char* key, const char* value)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->AddToStringList(section, key, value);
}
bool Host::RemoveBaseValueFromStringList(const char* section, const char* key, const char* value)
{
std::unique_lock lock(s_settings_mutex);
return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->RemoveFromStringList(section, key, value);
}
void Host::RemoveBaseSettingValue(const char* section, const char* key)
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->DeleteValue(section, key);
}
void Host::CommitBaseSettingChanges()
{
std::unique_lock lock(s_settings_mutex);
s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->Save();
}
std::string Host::GetStringSettingValue(const char* section, const char* key, const char* default_value /*= ""*/)
{
std::unique_lock lock(s_settings_mutex);
@ -221,8 +230,7 @@ void Host::Internal::UpdateEmuFolders()
if (VMManager::HasValidVM())
{
if (EmuFolders::Cheats != old_cheats_directory ||
EmuFolders::CheatsWS != old_cheats_ws_directory ||
if (EmuFolders::Cheats != old_cheats_directory || EmuFolders::CheatsWS != old_cheats_ws_directory ||
EmuFolders::CheatsNI != old_cheats_ni_directory)
{
VMManager::ReloadPatches(true, true);

View File

@ -29,6 +29,7 @@ public:
~INISettingsInterface() override;
const std::string& GetFileName() const { return m_filename; }
bool IsDirty() const { return m_dirty; }
bool Load();
bool Save() override;

View File

@ -32,12 +32,16 @@
#include "HostDisplay.h"
#include "imgui_internal.h"
#include "misc/cpp/imgui_stdlib.h"
#include <array>
#include <cmath>
#include <deque>
#include <mutex>
#include <variant>
namespace ImGuiFullscreen
{
using MessageDialogCallbackVariant = std::variant<InfoMessageDialogCallback, ConfirmMessageDialogCallback>;
static std::optional<Common::RGBA8Image> LoadTextureImage(const char* path);
static std::shared_ptr<HostDisplayTexture> UploadTexture(const char* path, const Common::RGBA8Image& image);
static void TextureLoaderThread();
@ -45,6 +49,7 @@ namespace ImGuiFullscreen
static void DrawFileSelector();
static void DrawChoiceDialog();
static void DrawInputDialog();
static void DrawMessageDialog();
static void DrawBackgroundProgressDialogs(ImVec2& position, float spacing);
static void DrawNotifications(ImVec2& position, float spacing);
static void DrawToast();
@ -110,6 +115,12 @@ namespace ImGuiFullscreen
static std::string s_input_dialog_ok_text;
static InputStringDialogCallback s_input_dialog_callback;
static bool s_message_dialog_open = false;
static std::string s_message_dialog_title;
static std::string s_message_dialog_message;
static std::array<std::string, 3> s_message_dialog_buttons;
static MessageDialogCallbackVariant s_message_dialog_callback;
struct FileSelectorItem
{
FileSelectorItem() = default;
@ -215,6 +226,7 @@ void ImGuiFullscreen::Shutdown()
s_notifications.clear();
s_background_progress_dialogs.clear();
CloseInputDialog();
CloseMessageDialog();
s_choice_dialog_open = false;
s_choice_dialog_checkable = false;
s_choice_dialog_title = {};
@ -459,6 +471,7 @@ void ImGuiFullscreen::EndLayout()
DrawFileSelector();
DrawChoiceDialog();
DrawInputDialog();
DrawMessageDialog();
const float notification_margin = LayoutScale(10.0f);
const float spacing = LayoutScale(10.0f);
@ -1839,9 +1852,13 @@ void ImGuiFullscreen::DrawInputDialog()
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup(s_input_dialog_title.c_str());
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f));
ImGui::PushFont(g_large_font);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(LAYOUT_MENU_BUTTON_X_PADDING, LAYOUT_MENU_BUTTON_Y_PADDING));
ImGui::PushStyleColor(ImGuiCol_Text, UIPrimaryTextColor);
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIPrimaryDarkColor);
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIPrimaryColor);
ImGui::PushStyleColor(ImGuiCol_PopupBg, UIBackgroundColor);
bool is_open = true;
if (ImGui::BeginPopupModal(s_input_dialog_title.c_str(), &is_open,
@ -1884,8 +1901,9 @@ void ImGuiFullscreen::DrawInputDialog()
if (!is_open)
CloseInputDialog();
ImGui::PopFont();
ImGui::PopStyleColor(4);
ImGui::PopStyleVar(2);
ImGui::PopFont();
}
void ImGuiFullscreen::CloseInputDialog()
@ -1902,6 +1920,125 @@ void ImGuiFullscreen::CloseInputDialog()
s_input_dialog_callback = {};
}
bool ImGuiFullscreen::IsMessageBoxDialogOpen()
{
return s_message_dialog_open;
}
void ImGuiFullscreen::OpenConfirmMessageDialog(
std::string title, std::string message, ConfirmMessageDialogCallback callback, std::string yes_button_text, std::string no_button_text)
{
CloseMessageDialog();
s_message_dialog_open = true;
s_message_dialog_title = std::move(title);
s_message_dialog_message = std::move(message);
s_message_dialog_callback = std::move(callback);
s_message_dialog_buttons[0] = std::move(yes_button_text);
s_message_dialog_buttons[1] = std::move(no_button_text);
}
void ImGuiFullscreen::OpenInfoMessageDialog(
std::string title, std::string message, InfoMessageDialogCallback callback, std::string button_text)
{
CloseMessageDialog();
s_message_dialog_open = true;
s_message_dialog_title = std::move(title);
s_message_dialog_message = std::move(message);
s_message_dialog_callback = std::move(callback);
s_message_dialog_buttons[0] = std::move(button_text);
}
void ImGuiFullscreen::OpenMessageDialog(std::string title, std::string message, MessageDialogCallback callback,
std::string first_button_text, std::string second_button_text, std::string third_button_text)
{
CloseMessageDialog();
s_message_dialog_open = true;
s_message_dialog_title = std::move(title);
s_message_dialog_message = std::move(message);
s_message_dialog_callback = std::move(callback);
s_message_dialog_buttons[0] = std::move(first_button_text);
s_message_dialog_buttons[1] = std::move(second_button_text);
s_message_dialog_buttons[2] = std::move(third_button_text);
}
void ImGuiFullscreen::CloseMessageDialog()
{
if (!s_message_dialog_open)
return;
s_message_dialog_open = false;
s_message_dialog_title = {};
s_message_dialog_message = {};
s_message_dialog_buttons = {};
s_message_dialog_callback = {};
}
void ImGuiFullscreen::DrawMessageDialog()
{
if (!s_message_dialog_open)
return;
const char* win_id = s_message_dialog_title.empty() ? "##messagedialog" : s_message_dialog_title.c_str();
ImGui::SetNextWindowSize(LayoutScale(700.0f, 0.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup(win_id);
ImGui::PushFont(g_large_font);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(LAYOUT_MENU_BUTTON_X_PADDING, LAYOUT_MENU_BUTTON_Y_PADDING));
ImGui::PushStyleColor(ImGuiCol_Text, UIPrimaryTextColor);
ImGui::PushStyleColor(ImGuiCol_TitleBg, UIPrimaryDarkColor);
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, UIPrimaryColor);
ImGui::PushStyleColor(ImGuiCol_PopupBg, UIBackgroundColor);
bool is_open = true;
const u32 flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
(s_message_dialog_title.empty() ? ImGuiWindowFlags_NoTitleBar : 0);
std::optional<s32> result;
if (ImGui::BeginPopupModal(win_id, &is_open, flags))
{
BeginMenuButtons();
ImGui::TextWrapped("%s", s_message_dialog_message.c_str());
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f));
for (s32 button_index = 0; button_index < static_cast<s32>(s_message_dialog_buttons.size()); button_index++)
{
if (!s_message_dialog_buttons[button_index].empty() && ActiveButton(s_message_dialog_buttons[button_index].c_str(), false))
{
result = button_index;
ImGui::CloseCurrentPopup();
}
}
EndMenuButtons();
ImGui::EndPopup();
}
ImGui::PopStyleColor(4);
ImGui::PopStyleVar(3);
ImGui::PopFont();
if (!is_open || result.has_value())
{
// have to move out in case they open another dialog in the callback
auto cb = (std::move(s_message_dialog_callback));
CloseMessageDialog();
if (std::holds_alternative<InfoMessageDialogCallback>(cb))
std::get<InfoMessageDialogCallback>(cb)();
else if (std::holds_alternative<ConfirmMessageDialogCallback>(cb))
std::get<ConfirmMessageDialogCallback>(cb)(result.value_or(1) == 0);
}
}
static float s_notification_vertical_position = 0.3f;
static float s_notification_vertical_direction = -1.0f;

View File

@ -15,6 +15,7 @@
#pragma once
#include "common/Pcsx2Defs.h"
#include "IconsFontAwesome5.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <functional>
@ -90,10 +91,7 @@ namespace ImGuiFullscreen
return ImVec2(g_layout_padding_left + x * g_layout_scale, g_layout_padding_top + y * g_layout_scale);
}
static __fi ImVec4 ModAlpha(const ImVec4& v, float a)
{
return ImVec4(v.x, v.y, v.z, a);
}
static __fi ImVec4 ModAlpha(const ImVec4& v, float a) { return ImVec4(v.x, v.y, v.z, a); }
/// Centers an image within the specified bounds, scaling up or down as needed.
ImRect CenterImage(const ImVec2& fit_size, const ImVec2& image_size);
@ -223,6 +221,18 @@ namespace ImGuiFullscreen
std::string title, std::string message, std::string caption, std::string ok_button_text, InputStringDialogCallback callback);
void CloseInputDialog();
using ConfirmMessageDialogCallback = std::function<void(bool)>;
using InfoMessageDialogCallback = std::function<void()>;
using MessageDialogCallback = std::function<void(s32)>;
bool IsMessageBoxDialogOpen();
void OpenConfirmMessageDialog(std::string title, std::string message, ConfirmMessageDialogCallback callback,
std::string yes_button_text = ICON_FA_CHECK " Yes", std::string no_button_text = ICON_FA_TIMES " No");
void OpenInfoMessageDialog(std::string title, std::string message, InfoMessageDialogCallback callback,
std::string button_text = ICON_FA_WINDOW_CLOSE " Close");
void OpenMessageDialog(std::string title, std::string message, MessageDialogCallback callback, std::string first_button_text,
std::string second_button_text, std::string third_button_text);
void CloseMessageDialog();
float GetNotificationVerticalPosition();
float GetNotificationVerticalDirection();
void SetNotificationVerticalPosition(float position, float direction);

View File

@ -23,6 +23,7 @@
#include "common/Console.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "common/SettingsInterface.h"
#include "common/StringUtil.h"
#include "common/Timer.h"
@ -386,3 +387,15 @@ void Host::UpdateLogging(bool disable_system_console)
UpdateLoggingSinks(system_console_enabled, file_logging_enabled);
}
void Host::SetDefaultLoggingSettings(SettingsInterface& si)
{
si.SetBoolValue("Logging", "EnableSystemConsole", false);
si.SetBoolValue("Logging", "EnableFileLogging", false);
si.SetBoolValue("Logging", "EnableTimestamps", true);
si.SetBoolValue("Logging", "EnableVerbose", false);
si.SetBoolValue("Logging", "EnableEEConsole", false);
si.SetBoolValue("Logging", "EnableIOPConsole", false);
si.SetBoolValue("Logging", "EnableInputRecordingLogs", true);
si.SetBoolValue("Logging", "EnableControllerLogs", false);
}

View File

@ -15,6 +15,8 @@
#pragma once
class SettingsInterface;
namespace Host
{
/// Updates the Console handler based on the current configuration.
@ -22,4 +24,7 @@ namespace Host
/// Initializes early console logging (for printing command line arguments).
void InitializeEarlyConsole();
/// Stores default logging settings to the specified file.
void SetDefaultLoggingSettings(SettingsInterface& si);
}

View File

@ -17,6 +17,7 @@
#include "common/Pcsx2Defs.h"
#include <functional>
#include <string>
#include <string_view>
#include <optional>
@ -73,4 +74,32 @@ namespace Host
/// Copies the provided text to the host's clipboard, if present.
bool CopyTextToClipboard(const std::string_view& text);
/// Requests settings reset. Can be called from any thread, will call back and apply on the CPU thread.
bool RequestResetSettings(bool folders, bool core, bool controllers, bool hotkeys, bool ui);
/// Requests a specific display window size.
void RequestResizeHostDisplay(s32 width, s32 height);
/// Safely executes a function on the VM thread.
void RunOnCPUThread(std::function<void()> function, bool block = false);
/// Asynchronously starts refreshing the game list.
void RefreshGameListAsync(bool invalidate_cache);
/// Cancels game list refresh, if there is one in progress.
void CancelGameListRefresh();
/// Requests shut down and exit of the hosting application. This may not actually exit,
/// if the user cancels the shutdown confirmation.
void RequestExit(bool save_state_if_running);
/// Requests shut down of the current virtual machine.
void RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state);
/// Returns true if the hosting application is currently fullscreen.
bool IsFullscreen();
/// Alters fullscreen state of hosting application.
void SetFullscreen(bool enabled);
} // namespace Host

View File

@ -40,7 +40,9 @@ namespace Host
void SetBaseFloatSettingValue(const char* section, const char* key, float value);
void SetBaseStringSettingValue(const char* section, const char* key, const char* value);
void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values);
void DeleteBaseSettingValue(const char* section, const char* key);
bool AddBaseValueToStringList(const char* section, const char* key, const char* value);
bool RemoveBaseValueFromStringList(const char* section, const char* key, const char* value);
void RemoveBaseSettingValue(const char* section, const char* key);
void CommitBaseSettingChanges();
// Settings access, thread-safe.

View File

@ -1231,21 +1231,19 @@ void Pcsx2Config::CopyConfig(const Pcsx2Config& cfg)
LimiterMode = cfg.LimiterMode;
}
void EmuFolders::SetDefaults()
void EmuFolders::SetDefaults(SettingsInterface& si)
{
Bios = Path::Combine(DataRoot, "bios");
Snapshots = Path::Combine(DataRoot, "snaps");
Savestates = Path::Combine(DataRoot, "sstates");
MemoryCards = Path::Combine(DataRoot, "memcards");
Logs = Path::Combine(DataRoot, "logs");
Cheats = Path::Combine(DataRoot, "cheats");
CheatsWS = Path::Combine(DataRoot, "cheats_ws");
CheatsNI = Path::Combine(DataRoot, "cheats_ni");
Covers = Path::Combine(DataRoot, "covers");
GameSettings = Path::Combine(DataRoot, "gamesettings");
Cache = Path::Combine(DataRoot, "cache");
Textures = Path::Combine(DataRoot, "textures");
InputProfiles = Path::Combine(DataRoot, "inputprofiles");
si.SetStringValue("Folders", "Bios", "bios");
si.SetStringValue("Folders", "Snapshots", "snaps");
si.SetStringValue("Folders", "Savestates", "sstates");
si.SetStringValue("Folders", "MemoryCards", "memcards");
si.SetStringValue("Folders", "Logs", "logs");
si.SetStringValue("Folders", "Cheats", "cheats");
si.SetStringValue("Folders", "CheatsWS", "cheats_ws");
si.SetStringValue("Folders", "CheatsNI", "cheats_ni");
si.SetStringValue("Folders", "Cache", "cache");
si.SetStringValue("Folders", "Textures", "textures");
si.SetStringValue("Folders", "InputProfiles", "inputprofiles");
}
static std::string LoadPathFromSettings(SettingsInterface& si, const std::string& root, const char* name, const char* def)
@ -1287,22 +1285,6 @@ void EmuFolders::LoadConfig(SettingsInterface& si)
Console.WriteLn("Input Profile Directory: %s", InputProfiles.c_str());
}
void EmuFolders::Save(SettingsInterface& si)
{
// convert back to relative
si.SetStringValue("Folders", "Bios", Path::MakeRelative(Bios, DataRoot).c_str());
si.SetStringValue("Folders", "Snapshots", Path::MakeRelative(Snapshots, DataRoot).c_str());
si.SetStringValue("Folders", "Savestates", Path::MakeRelative(Savestates, DataRoot).c_str());
si.SetStringValue("Folders", "MemoryCards", Path::MakeRelative(MemoryCards, DataRoot).c_str());
si.SetStringValue("Folders", "Logs", Path::MakeRelative(Logs, DataRoot).c_str());
si.SetStringValue("Folders", "Cheats", Path::MakeRelative(Cheats, DataRoot).c_str());
si.SetStringValue("Folders", "CheatsWS", Path::MakeRelative(CheatsWS, DataRoot).c_str());
si.SetStringValue("Folders", "CheatsNI", Path::MakeRelative(CheatsNI, DataRoot).c_str());
si.SetStringValue("Folders", "Cache", Path::MakeRelative(Cache, DataRoot).c_str());
si.SetStringValue("Folders", "Textures", Path::MakeRelative(Textures, DataRoot).c_str());
si.SetStringValue("Folders", "InputProfiles", Path::MakeRelative(InputProfiles, DataRoot).c_str());
}
bool EmuFolders::EnsureFoldersExist()
{
bool result = FileSystem::CreateDirectoryPath(Bios.c_str(), false);

View File

@ -234,29 +234,4 @@ namespace Host
/// Provided by the host; called when a state is saved, and the frontend should invalidate its save state cache.
void InvalidateSaveStateCache();
/// Requests a specific display window size.
void RequestResizeHostDisplay(s32 width, s32 height);
/// Safely executes a function on the VM thread.
void RunOnCPUThread(std::function<void()> function, bool block = false);
/// Asynchronously starts refreshing the game list.
void RefreshGameListAsync(bool invalidate_cache);
/// Cancels game list refresh, if there is one in progress.
void CancelGameListRefresh();
/// Requests shut down and exit of the hosting application. This may not actually exit,
/// if the user cancels the shutdown confirmation.
void RequestExit(bool save_state_if_running);
/// Requests shut down of the current virtual machine.
void RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state);
/// Returns true if the hosting application is currently fullscreen.
bool IsFullscreen();
/// Alters fullscreen state of hosting application.
void SetFullscreen(bool enabled);
}

View File

@ -186,6 +186,7 @@
<ClCompile Include="DEV9\sockets.cpp" />
<ClCompile Include="DEV9\net.cpp" />
<ClCompile Include="DEV9\Win32\tap-win32.cpp" />
<ClCompile Include="Frontend\CommonHost.cpp" />
<ClCompile Include="Frontend\D3D11HostDisplay.cpp" />
<ClCompile Include="Frontend\D3D12HostDisplay.cpp" />
<ClCompile Include="Frontend\FullscreenUI.cpp" />
@ -218,7 +219,7 @@
<ClCompile Include="GS\Renderers\Vulkan\GSTextureVK.cpp" />
<ClCompile Include="Host.cpp" />
<ClCompile Include="HostDisplay.cpp" />
<ClCompile Include="HostSettings.cpp" />
<ClCompile Include="Frontend\HostSettings.cpp" />
<ClCompile Include="IopGte.cpp" />
<ClCompile Include="PAD\Host\KeyStatus.cpp" />
<ClCompile Include="PAD\Host\PAD.cpp" />
@ -508,6 +509,7 @@
<ClInclude Include="DEV9\ThreadSafeMap.h" />
<ClInclude Include="DEV9\Win32\pcap_io_win32_funcs.h" />
<ClInclude Include="DEV9\Win32\tap.h" />
<ClInclude Include="Frontend\CommonHost.h" />
<ClInclude Include="Frontend\D3D11HostDisplay.h" />
<ClInclude Include="Frontend\D3D12HostDisplay.h" />
<ClInclude Include="Frontend\FullscreenUI.h" />

View File

@ -1205,7 +1205,7 @@
<ClCompile Include="USB\USBNull.cpp">
<Filter>System\Ps2\USB</Filter>
</ClCompile>
<ClCompile Include="HostSettings.cpp">
<ClCompile Include="Frontend\HostSettings.cpp">
<Filter>Host</Filter>
</ClCompile>
<ClCompile Include="VMManager.cpp">
@ -1281,6 +1281,9 @@
<ClCompile Include="Frontend\FullscreenUI.cpp">
<Filter>Host</Filter>
</ClCompile>
<ClCompile Include="Frontend\CommonHost.cpp">
<Filter>Host</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Patch.h">
@ -2131,6 +2134,9 @@
<ClInclude Include="Frontend\FullscreenUI.h">
<Filter>Host</Filter>
</ClInclude>
<ClInclude Include="Frontend\CommonHost.h">
<Filter>Host</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuildStep Include="rdebug\deci2.h">