From 84a937ae651aa5296535e8feffe47aa1f2b219ab Mon Sep 17 00:00:00 2001 From: TryTwo Date: Tue, 17 Sep 2024 23:29:13 -0700 Subject: [PATCH] Add GFX property tabs to game properties window, allowing them to be set to the user game ini. Additionally, refactor ConfigWidgets to reduce duplication. Refactor GameConfigWidget to use config system. Creates a layer outside the game config layer system and passes it to the created gfx widows, so as to not interfere with the global config system. Supports multiple game properties being open at once. Supports editing while a game is playing, but the options only save and update the active game when the window is closed. Right-clicking will remove a property from the game ini. --- .../Config/ConfigControls/ConfigBool.cpp | 8 +- .../Config/ConfigControls/ConfigBool.h | 2 + .../Config/ConfigControls/ConfigChoice.cpp | 20 +- .../Config/ConfigControls/ConfigChoice.h | 9 +- .../Config/ConfigControls/ConfigControl.h | 47 +- .../ConfigControls/ConfigFloatSlider.cpp | 5 +- .../Config/ConfigControls/ConfigFloatSlider.h | 3 +- .../Config/ConfigControls/ConfigInteger.cpp | 8 +- .../Config/ConfigControls/ConfigInteger.h | 3 + .../Config/ConfigControls/ConfigRadio.cpp | 5 +- .../Config/ConfigControls/ConfigRadio.h | 3 +- .../Config/ConfigControls/ConfigSlider.cpp | 8 +- .../Config/ConfigControls/ConfigSlider.h | 3 + .../DolphinQt/Config/GameConfigWidget.cpp | 442 ++++++++---------- .../Core/DolphinQt/Config/GameConfigWidget.h | 58 +-- .../Config/Graphics/AdvancedWidget.cpp | 173 ++++--- .../Config/Graphics/AdvancedWidget.h | 20 +- .../Config/Graphics/EnhancementsWidget.cpp | 48 +- .../Config/Graphics/EnhancementsWidget.h | 8 + .../Config/Graphics/GeneralWidget.cpp | 81 ++-- .../DolphinQt/Config/Graphics/GeneralWidget.h | 15 +- .../DolphinQt/Config/Graphics/HacksWidget.cpp | 53 ++- .../DolphinQt/Config/Graphics/HacksWidget.h | 9 + Source/Core/DolphinQt/GameList/GameList.cpp | 6 +- 24 files changed, 573 insertions(+), 464 deletions(-) diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigBool.cpp b/Source/Core/DolphinQt/Config/ConfigControls/ConfigBool.cpp index 0f99284297..4fad525e6f 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigBool.cpp +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigBool.cpp @@ -4,7 +4,13 @@ #include "DolphinQt/Config/ConfigControls/ConfigBool.h" ConfigBool::ConfigBool(const QString& label, const Config::Info& setting, bool reverse) - : ConfigControl(label, setting.GetLocation()), m_setting(setting), m_reverse(reverse) + : ConfigBool(label, setting, nullptr, reverse) +{ +} + +ConfigBool::ConfigBool(const QString& label, const Config::Info& setting, + Config::Layer* layer, bool reverse) + : ConfigControl(label, setting.GetLocation(), layer), m_setting(setting), m_reverse(reverse) { setChecked(ReadValue(setting) ^ reverse); diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigBool.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigBool.h index 467220e488..304f1a9b1f 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigBool.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigBool.h @@ -17,6 +17,8 @@ class ConfigBool final : public ConfigControl Q_OBJECT public: ConfigBool(const QString& label, const Config::Info& setting, bool reverse = false); + ConfigBool(const QString& label, const Config::Info& setting, Config::Layer* layer, + bool reverse = false); protected: void OnConfigChanged() override; diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.cpp b/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.cpp index a26b87b46e..c2652563d1 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.cpp +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.cpp @@ -5,8 +5,9 @@ #include -ConfigChoice::ConfigChoice(const QStringList& options, const Config::Info& setting) - : ConfigControl(setting.GetLocation()), m_setting(setting) +ConfigChoice::ConfigChoice(const QStringList& options, const Config::Info& setting, + Config::Layer* layer) + : ConfigControl(setting.GetLocation(), layer), m_setting(setting) { addItems(options); setCurrentIndex(ReadValue(setting)); @@ -25,8 +26,9 @@ void ConfigChoice::OnConfigChanged() } ConfigStringChoice::ConfigStringChoice(const std::vector& options, - const Config::Info& setting) - : ConfigControl(setting.GetLocation()), m_setting(setting), m_text_is_data(true) + const Config::Info& setting, + Config::Layer* layer) + : ConfigControl(setting.GetLocation(), layer), m_setting(setting), m_text_is_data(true) { for (const auto& op : options) addItem(QString::fromStdString(op)); @@ -36,8 +38,9 @@ ConfigStringChoice::ConfigStringChoice(const std::vector& options, } ConfigStringChoice::ConfigStringChoice(const std::vector>& options, - const Config::Info& setting) - : ConfigControl(setting.GetLocation()), m_setting(setting), m_text_is_data(false) + const Config::Info& setting, + Config::Layer* layer) + : ConfigControl(setting.GetLocation(), layer), m_setting(setting), m_text_is_data(false) { for (const auto& [option_text, option_data] : options) addItem(option_text, option_data); @@ -57,9 +60,10 @@ void ConfigStringChoice::Update(int index) void ConfigStringChoice::Load() { const QString setting_value = QString::fromStdString(ReadValue(m_setting)); - const int index = m_text_is_data ? findText(setting_value) : findData(setting_value); - const QSignalBlocker blocker(this); + + // This can be called publicly. + const QSignalBlocker block(this); setCurrentIndex(index); } diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.h index 930e7aef10..fa2bdf6f88 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigChoice.h @@ -20,7 +20,8 @@ class ConfigChoice final : public ConfigControl { Q_OBJECT public: - ConfigChoice(const QStringList& options, const Config::Info& setting); + ConfigChoice(const QStringList& options, const Config::Info& setting, + Config::Layer* layer = nullptr); protected: void OnConfigChanged() override; @@ -36,16 +37,16 @@ class ConfigStringChoice final : public ConfigControl Q_OBJECT public: ConfigStringChoice(const std::vector& options, - const Config::Info& setting); + const Config::Info& setting, Config::Layer* layer = nullptr); ConfigStringChoice(const std::vector>& options, - const Config::Info& setting); + const Config::Info& setting, Config::Layer* layer = nullptr); + void Load(); protected: void OnConfigChanged() override; private: void Update(int index); - void Load(); const Config::Info& m_setting; bool m_text_is_data = false; diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigControl.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigControl.h index 4100781cfe..1be0a8fa19 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigControl.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigControl.h @@ -8,6 +8,7 @@ #include #include "Common/Config/Enums.h" +#include "Common/Config/Layer.h" #include "DolphinQt/Settings.h" namespace Config @@ -21,14 +22,19 @@ template class ConfigControl : public Derived { public: - ConfigControl(const Config::Location& location) : m_location(location) { ConnectConfig(); } - ConfigControl(const QString& label, const Config::Location& location) - : Derived(label), m_location(location) + ConfigControl(const Config::Location& location, Config::Layer* layer) + : m_location(location), m_layer(layer) { ConnectConfig(); } - ConfigControl(const Qt::Orientation& orient, const Config::Location& location) - : Derived(orient), m_location(location) + ConfigControl(const QString& label, const Config::Location& location, Config::Layer* layer) + : Derived(label), m_location(location), m_layer(layer) + { + ConnectConfig(); + } + ConfigControl(const Qt::Orientation& orient, const Config::Location& location, + Config::Layer* layer) + : Derived(orient), m_location(location), m_layer(layer) { ConnectConfig(); } @@ -51,22 +57,49 @@ protected: template void SaveValue(const Config::Info& setting, const T& value) { + if (m_layer != nullptr) + { + m_layer->Set(m_location, value); + Config::OnConfigChanged(); + return; + } + Config::SetBaseOrCurrent(setting, value); } template const T ReadValue(const Config::Info& setting) const { + if (m_layer != nullptr) + return m_layer->Get(setting); + return Config::Get(setting); } - virtual void OnConfigChanged() {}; + virtual void OnConfigChanged(){}; private: bool IsConfigLocal() const { - return Config::GetActiveLayerForConfig(m_location) != Config::LayerType::Base; + if (m_layer != nullptr) + return m_layer->Exists(m_location); + else + return Config::GetActiveLayerForConfig(m_location) != Config::LayerType::Base; + } + + void mousePressEvent(QMouseEvent* event) override + { + if (m_layer != nullptr && event->button() == Qt::RightButton) + { + m_layer->DeleteKey(m_location); + Config::OnConfigChanged(); + } + else + { + Derived::mousePressEvent(event); + } } const Config::Location m_location; + Config::Layer* m_layer; }; diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.cpp b/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.cpp index b8aa2c82fc..e5211d00bb 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.cpp +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.cpp @@ -4,8 +4,9 @@ #include "DolphinQt/Config/ConfigControls/ConfigFloatSlider.h" ConfigFloatSlider::ConfigFloatSlider(float minimum, float maximum, - const Config::Info& setting, float step) - : ConfigControl(Qt::Horizontal, setting.GetLocation()), m_minimum(minimum), m_step(step), + const Config::Info& setting, float step, + Config::Layer* layer) + : ConfigControl(Qt::Horizontal, setting.GetLocation(), layer), m_minimum(minimum), m_step(step), m_setting(setting) { const float range = maximum - minimum; diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.h index 3c38e34095..f68b018379 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigFloatSlider.h @@ -18,7 +18,8 @@ class ConfigFloatSlider final : public ConfigControl { Q_OBJECT public: - ConfigFloatSlider(float minimum, float maximum, const Config::Info& setting, float step); + ConfigFloatSlider(float minimum, float maximum, const Config::Info& setting, float step, + Config::Layer* layer = nullptr); void Update(int value); // Returns the adjusted float value diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigInteger.cpp b/Source/Core/DolphinQt/Config/ConfigControls/ConfigInteger.cpp index ba85e64617..8d724505e3 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigInteger.cpp +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigInteger.cpp @@ -4,7 +4,13 @@ #include "DolphinQt/Config/ConfigControls/ConfigInteger.h" ConfigInteger::ConfigInteger(int minimum, int maximum, const Config::Info& setting, int step) - : ConfigControl(setting.GetLocation()), m_setting(setting) + : ConfigInteger(minimum, maximum, setting, nullptr, step) +{ +} + +ConfigInteger::ConfigInteger(int minimum, int maximum, const Config::Info& setting, + Config::Layer* layer, int step) + : ConfigControl(setting.GetLocation(), layer), m_setting(setting) { setMinimum(minimum); setMaximum(maximum); diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigInteger.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigInteger.h index 21100c9af1..2979423f74 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigInteger.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigInteger.h @@ -17,6 +17,9 @@ class ConfigInteger final : public ConfigControl Q_OBJECT public: ConfigInteger(int minimum, int maximum, const Config::Info& setting, int step = 1); + ConfigInteger(int minimum, int maximum, const Config::Info& setting, Config::Layer* layer, + int step = 1); + void Update(int value); protected: diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigRadio.cpp b/Source/Core/DolphinQt/Config/ConfigControls/ConfigRadio.cpp index baaf7e6f48..eba9de283c 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigRadio.cpp +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigRadio.cpp @@ -3,8 +3,9 @@ #include "DolphinQt/Config/ConfigControls/ConfigRadio.h" -ConfigRadioInt::ConfigRadioInt(const QString& label, const Config::Info& setting, int value) - : ConfigControl(label, setting.GetLocation()), m_setting(setting), m_value(value) +ConfigRadioInt::ConfigRadioInt(const QString& label, const Config::Info& setting, int value, + Config::Layer* layer) + : ConfigControl(label, setting.GetLocation(), layer), m_setting(setting), m_value(value) { setChecked(ReadValue(setting) == value); diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigRadio.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigRadio.h index 8b28f2c106..c6b0e8835c 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigRadio.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigRadio.h @@ -16,7 +16,8 @@ class ConfigRadioInt final : public ConfigControl { Q_OBJECT public: - ConfigRadioInt(const QString& label, const Config::Info& setting, int value); + ConfigRadioInt(const QString& label, const Config::Info& setting, int value, + Config::Layer* layer = nullptr); signals: // Since selecting a new radio button deselects the old one, ::toggled will generate two signals. diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigSlider.cpp b/Source/Core/DolphinQt/Config/ConfigControls/ConfigSlider.cpp index a52b42d4f4..9192410e03 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigSlider.cpp +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigSlider.cpp @@ -4,7 +4,13 @@ #include "DolphinQt/Config/ConfigControls/ConfigSlider.h" ConfigSlider::ConfigSlider(int minimum, int maximum, const Config::Info& setting, int tick) - : ConfigControl(Qt::Horizontal, setting.GetLocation()), m_setting(setting) + : ConfigSlider(minimum, maximum, setting, nullptr, tick) +{ +} + +ConfigSlider::ConfigSlider(int minimum, int maximum, const Config::Info& setting, + Config::Layer* layer, int tick) + : ConfigControl(Qt::Horizontal, setting.GetLocation(), layer), m_setting(setting) { setMinimum(minimum); diff --git a/Source/Core/DolphinQt/Config/ConfigControls/ConfigSlider.h b/Source/Core/DolphinQt/Config/ConfigControls/ConfigSlider.h index ebb02391e8..7ac81d03d5 100644 --- a/Source/Core/DolphinQt/Config/ConfigControls/ConfigSlider.h +++ b/Source/Core/DolphinQt/Config/ConfigControls/ConfigSlider.h @@ -17,6 +17,9 @@ class ConfigSlider final : public ConfigControl Q_OBJECT public: ConfigSlider(int minimum, int maximum, const Config::Info& setting, int tick = 0); + ConfigSlider(int minimum, int maximum, const Config::Info& setting, Config::Layer* layer, + int tick = 0); + void Update(int value); protected: diff --git a/Source/Core/DolphinQt/Config/GameConfigWidget.cpp b/Source/Core/DolphinQt/Config/GameConfigWidget.cpp index ce56a357be..30109f1b9c 100644 --- a/Source/Core/DolphinQt/Config/GameConfigWidget.cpp +++ b/Source/Core/DolphinQt/Config/GameConfigWidget.cpp @@ -3,37 +3,39 @@ #include "DolphinQt/Config/GameConfigWidget.h" -#include -#include +#include #include +#include +#include #include -#include -#include -#include #include +#include +#include #include #include "Common/CommonPaths.h" +#include "Common/Config/Config.h" +#include "Common/Config/Layer.h" #include "Common/FileUtil.h" +#include "Core/Config/GraphicsSettings.h" +#include "Core/Config/MainSettings.h" #include "Core/ConfigLoaders/GameConfigLoader.h" #include "Core/ConfigManager.h" - +#include "DolphinQt/Config/ConfigControls/ConfigBool.h" +#include "DolphinQt/Config/ConfigControls/ConfigChoice.h" +#include "DolphinQt/Config/ConfigControls/ConfigInteger.h" +#include "DolphinQt/Config/ConfigControls/ConfigRadio.h" #include "DolphinQt/Config/ConfigControls/ConfigSlider.h" #include "DolphinQt/Config/GameConfigEdit.h" +#include "DolphinQt/Config/Graphics/AdvancedWidget.h" +#include "DolphinQt/Config/Graphics/EnhancementsWidget.h" +#include "DolphinQt/Config/Graphics/GeneralWidget.h" +#include "DolphinQt/Config/Graphics/HacksWidget.h" +#include "DolphinQt/QtUtils/WrapInScrollArea.h" #include "UICommon/GameFile.h" -constexpr int DETERMINISM_NOT_SET_INDEX = 0; -constexpr int DETERMINISM_AUTO_INDEX = 1; -constexpr int DETERMINISM_NONE_INDEX = 2; -constexpr int DETERMINISM_FAKE_COMPLETION_INDEX = 3; - -constexpr const char* DETERMINISM_NOT_SET_STRING = ""; -constexpr const char* DETERMINISM_AUTO_STRING = "auto"; -constexpr const char* DETERMINISM_NONE_STRING = "none"; -constexpr const char* DETERMINISM_FAKE_COMPLETION_STRING = "fake-completion"; - static void PopulateTab(QTabWidget* tab, const std::string& path, std::string& game_id, u16 revision, bool read_only) { @@ -55,46 +57,62 @@ GameConfigWidget::GameConfigWidget(const UICommon::GameFile& game) : m_game(game m_gameini_local_path = QString::fromStdString(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"); + m_layer = std::make_unique( + ConfigLoaders::GenerateLocalGameConfigLoader(m_game_id, m_game.GetRevision())); + m_global_layer = std::make_unique( + ConfigLoaders::GenerateGlobalGameConfigLoader(m_game_id, m_game.GetRevision())); + CreateWidgets(); - LoadSettings(); - ConnectWidgets(); + connect(&Settings::Instance(), &Settings::ConfigChanged, this, &GameConfigWidget::LoadSettings); PopulateTab(m_default_tab, File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP, m_game_id, m_game.GetRevision(), true); PopulateTab(m_local_tab, File::GetUserPath(D_GAMESETTINGS_IDX), m_game_id, m_game.GetRevision(), false); - // Always give the user the opportunity to create a new INI - if (m_local_tab->count() == 0) + bool game_id_tab = false; + for (int i = 0; i < m_local_tab->count(); i++) { + if (m_local_tab->tabText(i).toStdString() == m_game_id + ".ini") + game_id_tab = true; + } + + if (game_id_tab == false) + { + // Create new local game ini tab if none exists. auto* edit = new GameConfigEdit( nullptr, QString::fromStdString(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"), false); m_local_tab->addTab(edit, QString::fromStdString(m_game_id + ".ini")); } + + // Fails to change font if it's directly called at this time. Is there a better workaround? + QTimer::singleShot(100, this, [this]() { + SetItalics(); + Config::OnConfigChanged(); + }); } void GameConfigWidget::CreateWidgets() { - // General - m_refresh_config = new QPushButton(tr("Refresh")); - + Config::Layer* layer = m_layer.get(); // Core auto* core_box = new QGroupBox(tr("Core")); auto* core_layout = new QGridLayout; core_box->setLayout(core_layout); - m_enable_dual_core = new QCheckBox(tr("Enable Dual Core")); - m_enable_mmu = new QCheckBox(tr("Enable MMU")); - m_enable_fprf = new QCheckBox(tr("Enable FPRF")); - m_sync_gpu = new QCheckBox(tr("Synchronize GPU thread")); - m_emulate_disc_speed = new QCheckBox(tr("Emulate Disc Speed")); - m_use_dsp_hle = new QCheckBox(tr("DSP HLE (fast)")); - m_manual_texture_sampling = new QCheckBox(tr("Manual Texture Sampling")); - m_deterministic_dual_core = new QComboBox; + m_enable_dual_core = new ConfigBool(tr("Enable Dual Core"), Config::MAIN_CPU_THREAD, layer); + m_enable_mmu = new ConfigBool(tr("Enable MMU"), Config::MAIN_MMU, layer); + m_enable_fprf = new ConfigBool(tr("Enable FPRF"), Config::MAIN_FPRF, layer); + m_sync_gpu = new ConfigBool(tr("Synchronize GPU thread"), Config::MAIN_SYNC_GPU, layer); + m_emulate_disc_speed = + new ConfigBool(tr("Emulate Disc Speed"), Config::MAIN_FAST_DISC_SPEED, layer, true); + m_use_dsp_hle = new ConfigBool(tr("DSP HLE (fast)"), Config::MAIN_DSP_HLE, layer); - for (const auto& item : {tr("Not Set"), tr("auto"), tr("none"), tr("fake-completion")}) - m_deterministic_dual_core->addItem(item); + const std::vector choice{tr("auto").toStdString(), tr("none").toStdString(), + tr("fake-completion").toStdString()}; + m_deterministic_dual_core = + new ConfigStringChoice(choice, Config::MAIN_GPU_DETERMINISM_MODE, layer); m_enable_mmu->setToolTip(tr( "Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = Fast)")); @@ -114,24 +132,18 @@ void GameConfigWidget::CreateWidgets() core_layout->addWidget(m_sync_gpu, 3, 0); core_layout->addWidget(m_emulate_disc_speed, 4, 0); core_layout->addWidget(m_use_dsp_hle, 5, 0); - core_layout->addWidget(m_manual_texture_sampling, 6, 0); - core_layout->addWidget(new QLabel(tr("Deterministic dual core:")), 7, 0); - core_layout->addWidget(m_deterministic_dual_core, 7, 1); + core_layout->addWidget(new QLabel(tr("Deterministic dual core:")), 6, 0); + core_layout->addWidget(m_deterministic_dual_core, 6, 1); // Stereoscopy auto* stereoscopy_box = new QGroupBox(tr("Stereoscopy")); auto* stereoscopy_layout = new QGridLayout; stereoscopy_box->setLayout(stereoscopy_layout); - m_depth_slider = new QSlider(Qt::Horizontal); - - m_depth_slider->setMinimum(100); - m_depth_slider->setMaximum(200); - - m_convergence_spin = new QSpinBox; - m_convergence_spin->setMinimum(0); - m_convergence_spin->setMaximum(INT32_MAX); - m_use_monoscopic_shadows = new QCheckBox(tr("Monoscopic Shadows")); + m_depth_slider = new ConfigSlider(100, 200, Config::GFX_STEREO_DEPTH_PERCENTAGE, layer); + m_convergence_spin = new ConfigInteger(0, INT32_MAX, Config::GFX_STEREO_CONVERGENCE, layer); + m_use_monoscopic_shadows = + new ConfigBool(tr("Monoscopic Shadows"), Config::GFX_STEREO_EFB_MONO_DEPTH, layer); m_depth_slider->setToolTip( tr("This value is multiplied with the depth set in the graphics configuration.")); @@ -146,31 +158,15 @@ void GameConfigWidget::CreateWidgets() stereoscopy_layout->addWidget(m_convergence_spin, 1, 1); stereoscopy_layout->addWidget(m_use_monoscopic_shadows, 2, 0); - auto* settings_box = new QGroupBox(tr("Game-Specific Settings")); - auto* settings_layout = new QVBoxLayout; - settings_box->setLayout(settings_layout); - - settings_layout->addWidget( - new QLabel(tr("These settings override core Dolphin settings.\nUndetermined means the game " - "uses Dolphin's setting."))); - settings_layout->addWidget(core_box); - settings_layout->addWidget(stereoscopy_box); - - auto* general_layout = new QGridLayout; - - general_layout->addWidget(settings_box, 0, 0, 1, -1); - - general_layout->addWidget(m_refresh_config, 1, 0, 1, -1); - - for (QCheckBox* item : - {m_enable_dual_core, m_enable_mmu, m_enable_fprf, m_sync_gpu, m_emulate_disc_speed, - m_use_dsp_hle, m_manual_texture_sampling, m_use_monoscopic_shadows}) - item->setTristate(true); + auto* general_layout = new QVBoxLayout; + general_layout->addWidget(core_box); + general_layout->addWidget(stereoscopy_box); + general_layout->addStretch(); auto* general_widget = new QWidget; general_widget->setLayout(general_layout); - // Advanced + // Editor tab auto* advanced_layout = new QVBoxLayout; auto* default_group = new QGroupBox(tr("Default Config (Read Only)")); @@ -196,207 +192,175 @@ void GameConfigWidget::CreateWidgets() auto* layout = new QVBoxLayout; auto* tab_widget = new QTabWidget; - tab_widget->addTab(general_widget, tr("General")); - tab_widget->addTab(advanced_widget, tr("Editor")); + // GFX settings tabs. Placed in a QWidget for consistent margins. + auto* gfx_tab_holder = new QWidget; + auto* gfx_layout = new QVBoxLayout; + gfx_tab_holder->setLayout(gfx_layout); + tab_widget->addTab(gfx_tab_holder, tr("Graphics")); + + auto* gfx_tabs = new QTabWidget; + + gfx_tabs->addTab(GetWrappedWidget(new GeneralWidget(this, m_layer.get()), this, 125, 100), + tr("General")); + gfx_tabs->addTab(GetWrappedWidget(new EnhancementsWidget(this, m_layer.get()), this, 125, 100), + tr("Enhancements")); + gfx_tabs->addTab(GetWrappedWidget(new HacksWidget(this, m_layer.get()), this, 125, 100), + tr("Hacks")); + gfx_tabs->addTab(GetWrappedWidget(new AdvancedWidget(this, m_layer.get()), this, 125, 100), + tr("Advanced")); + const int editor_index = tab_widget->addTab(advanced_widget, tr("Editor")); + gfx_layout->addWidget(gfx_tabs); + + connect(tab_widget, &QTabWidget::currentChanged, this, [this, editor_index](int index) { + // Update the ini editor after editing other tabs. + if (index == editor_index) + { + // Layer only auto-saves when it is destroyed. + m_layer->Save(); + + // There can be multiple ini loaded for a game, only replace the one related to the game + // ini being edited. + for (int i = 0; i < m_local_tab->count(); i++) + { + if (m_local_tab->tabText(i).toStdString() == m_game_id + ".ini") + { + m_local_tab->removeTab(i); + + auto* edit = new GameConfigEdit( + nullptr, + QString::fromStdString(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"), + false); + + m_local_tab->insertTab(i, edit, QString::fromStdString(m_game_id + ".ini")); + break; + } + } + } + + // Update other tabs after using ini editor. + if (m_prev_tab_index == editor_index) + { + // Load won't clear deleted keys, so everything is wiped before loading. + m_layer->DeleteAllKeys(); + m_layer->Load(); + Config::OnConfigChanged(); + } + + m_prev_tab_index = index; + }); + + const QString help_msg = tr( + "Italics mark default game settings, bold marks user settings.\nRight-click to remove user " + "settings.\nGraphics tabs don't display the value of a default game setting.\nAnti-Aliasing " + "settings are disabled when the global graphics backend doesn't " + "match the game setting."); + + auto help_icon = style()->standardIcon(QStyle::SP_MessageBoxQuestion); + auto* help_label = new QLabel(tr("These settings override core Dolphin settings.")); + help_label->setToolTip(help_msg); + auto help_label_icon = new QLabel(); + help_label_icon->setPixmap(help_icon.pixmap(12, 12)); + help_label_icon->setToolTip(help_msg); + auto* help_layout = new QHBoxLayout(); + help_layout->addWidget(help_label); + help_layout->addWidget(help_label_icon); + help_layout->addStretch(); + + layout->addLayout(help_layout); layout->addWidget(tab_widget); - setLayout(layout); } -void GameConfigWidget::ConnectWidgets() +GameConfigWidget::~GameConfigWidget() { - // Buttons - connect(m_refresh_config, &QPushButton::clicked, this, &GameConfigWidget::LoadSettings); + // Destructor saves the layer to file. + m_layer.reset(); - for (QCheckBox* box : - {m_enable_dual_core, m_enable_mmu, m_enable_fprf, m_sync_gpu, m_emulate_disc_speed, - m_use_dsp_hle, m_manual_texture_sampling, m_use_monoscopic_shadows}) - connect(box, &QCheckBox::stateChanged, this, &GameConfigWidget::SaveSettings); - - connect(m_deterministic_dual_core, &QComboBox::currentIndexChanged, this, - &GameConfigWidget::SaveSettings); - connect(m_depth_slider, &QSlider::valueChanged, this, &GameConfigWidget::SaveSettings); - connect(m_convergence_spin, &QSpinBox::valueChanged, this, &GameConfigWidget::SaveSettings); -} - -void GameConfigWidget::LoadCheckBox(QCheckBox* checkbox, const std::string& section, - const std::string& key, bool reverse) -{ - bool checked; - if (m_gameini_local.GetOrCreateSection(section)->Get(key, &checked)) - return checkbox->setCheckState(checked ^ reverse ? Qt::Checked : Qt::Unchecked); - - if (m_gameini_default.GetOrCreateSection(section)->Get(key, &checked)) - return checkbox->setCheckState(checked ^ reverse ? Qt::Checked : Qt::Unchecked); - checkbox->setCheckState(Qt::PartiallyChecked); -} - -void GameConfigWidget::SaveCheckBox(QCheckBox* checkbox, const std::string& section, - const std::string& key, bool reverse) -{ - // Delete any existing entries from the local gameini if checkbox is undetermined. - // Otherwise, write the current value to the local gameini if the value differs from the default - // gameini values. - // Delete any existing entry from the local gameini if the value does not differ from the default - // gameini value. - - if (checkbox->checkState() == Qt::PartiallyChecked) + // If a game is running and the game properties window is closed, update local game layer with + // any new changes. Not sure if doing it more frequently is safe. + auto local_layer = Config::GetLayer(Config::LayerType::LocalGame); + if (local_layer && SConfig::GetInstance().GetGameID() == m_game_id) { - m_gameini_local.DeleteKey(section, key); - return; + local_layer->DeleteAllKeys(); + local_layer->Load(); + Config::OnConfigChanged(); } - bool checked = (checkbox->checkState() == Qt::Checked) ^ reverse; - - if (m_gameini_default.Exists(section, key)) - { - bool default_value; - m_gameini_default.GetOrCreateSection(section)->Get(key, &default_value); - - if (default_value != checked) - m_gameini_local.GetOrCreateSection(section)->Set(key, checked); - else - m_gameini_local.DeleteKey(section, key); - - return; - } - - m_gameini_local.GetOrCreateSection(section)->Set(key, checked); + // Delete empty configs + if (File::GetSize(m_gameini_local_path.toStdString()) == 0) + File::Delete(m_gameini_local_path.toStdString()); } void GameConfigWidget::LoadSettings() { - // Reload config - m_gameini_local = SConfig::LoadLocalGameIni(m_game_id, m_game.GetRevision()); - m_gameini_default = SConfig::LoadDefaultGameIni(m_game_id, m_game.GetRevision()); + // Load globals + auto update_bool = [this](auto config, bool reverse = false) { + const Config::Location& setting = config->GetLocation(); - // Load game-specific settings + // Don't overwrite local with global + if (m_layer->Exists(setting) || !m_global_layer->Exists(setting)) + return; - // Core - LoadCheckBox(m_enable_dual_core, "Core", "CPUThread"); - LoadCheckBox(m_enable_mmu, "Core", "MMU"); - LoadCheckBox(m_enable_fprf, "Core", "FPRF"); - LoadCheckBox(m_sync_gpu, "Core", "SyncGPU"); - LoadCheckBox(m_emulate_disc_speed, "Core", "FastDiscSpeed", true); - LoadCheckBox(m_use_dsp_hle, "Core", "DSPHLE"); - LoadCheckBox(m_manual_texture_sampling, "Video_Hacks", "FastTextureSampling", true); + std::optional value = m_global_layer->Get(config->GetLocation()); - std::string determinism_mode; + if (value.has_value()) + { + const QSignalBlocker blocker(config); + config->setChecked(value.value() ^ reverse); + } + }; - int determinism_index = DETERMINISM_NOT_SET_INDEX; + auto update_int = [this](auto config) { + const Config::Location& setting = config->GetLocation(); - m_gameini_default.GetIfExists("Core", "GPUDeterminismMode", &determinism_mode); - m_gameini_local.GetIfExists("Core", "GPUDeterminismMode", &determinism_mode); + if (m_layer->Exists(setting) || !m_global_layer->Exists(setting)) + return; - if (determinism_mode == DETERMINISM_AUTO_STRING) + std::optional value = m_global_layer->Get(setting); + + if (value.has_value()) + { + const QSignalBlocker blocker(config); + config->setValue(value.value()); + } + }; + + for (ConfigBool* config : {m_enable_dual_core, m_enable_mmu, m_enable_fprf, m_sync_gpu, + m_use_dsp_hle, m_use_monoscopic_shadows}) { - determinism_index = DETERMINISM_AUTO_INDEX; - } - else if (determinism_mode == DETERMINISM_NONE_STRING) - { - determinism_index = DETERMINISM_NONE_INDEX; - } - else if (determinism_mode == DETERMINISM_FAKE_COMPLETION_STRING) - { - determinism_index = DETERMINISM_FAKE_COMPLETION_INDEX; + update_bool(config); } - m_deterministic_dual_core->setCurrentIndex(determinism_index); + update_bool(m_emulate_disc_speed, true); - // Stereoscopy - int depth_percentage = 100; - - m_gameini_default.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &depth_percentage); - m_gameini_local.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &depth_percentage); - - m_depth_slider->setValue(depth_percentage); - - int convergence = 0; - - m_gameini_default.GetIfExists("Video_Stereoscopy", "StereoConvergence", &convergence); - m_gameini_local.GetIfExists("Video_Stereoscopy", "StereoConvergence", &convergence); - - m_convergence_spin->setValue(convergence); - - LoadCheckBox(m_use_monoscopic_shadows, "Video_Stereoscopy", "StereoEFBMonoDepth"); + update_int(m_depth_slider); + update_int(m_convergence_spin); } -void GameConfigWidget::SaveSettings() +void GameConfigWidget::SetItalics() { - // Core - SaveCheckBox(m_enable_dual_core, "Core", "CPUThread"); - SaveCheckBox(m_enable_mmu, "Core", "MMU"); - SaveCheckBox(m_enable_fprf, "Core", "FPRF"); - SaveCheckBox(m_sync_gpu, "Core", "SyncGPU"); - SaveCheckBox(m_emulate_disc_speed, "Core", "FastDiscSpeed", true); - SaveCheckBox(m_use_dsp_hle, "Core", "DSPHLE"); - SaveCheckBox(m_manual_texture_sampling, "Video_Hacks", "FastTextureSampling", true); + // Mark system game settings with italics. Called once because it should never change. + auto italics = [this](auto config) { + if (!m_global_layer->Exists(config->GetLocation())) + return; - int determinism_num = m_deterministic_dual_core->currentIndex(); + QFont ifont = config->font(); + ifont.setItalic(true); + config->setFont(ifont); + }; - std::string determinism_mode = DETERMINISM_NOT_SET_STRING; - - switch (determinism_num) - { - case DETERMINISM_AUTO_INDEX: - determinism_mode = DETERMINISM_AUTO_STRING; - break; - case DETERMINISM_NONE_INDEX: - determinism_mode = DETERMINISM_NONE_STRING; - break; - case DETERMINISM_FAKE_COMPLETION_INDEX: - determinism_mode = DETERMINISM_FAKE_COMPLETION_STRING; - break; - } - - if (determinism_mode != DETERMINISM_NOT_SET_STRING) - { - std::string default_mode = DETERMINISM_NOT_SET_STRING; - if (!(m_gameini_default.GetIfExists("Core", "GPUDeterminismMode", &default_mode) && - default_mode == determinism_mode)) - { - m_gameini_local.GetOrCreateSection("Core")->Set("GPUDeterminismMode", determinism_mode); - } - } - else - { - m_gameini_local.DeleteKey("Core", "GPUDeterminismMode"); - } - - // Stereoscopy - int depth_percentage = m_depth_slider->value(); - - if (depth_percentage != 100) - { - int default_value = 0; - if (!(m_gameini_default.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", - &default_value) && - default_value == depth_percentage)) - { - m_gameini_local.GetOrCreateSection("Video_Stereoscopy") - ->Set("StereoDepthPercentage", depth_percentage); - } - } - - int convergence = m_convergence_spin->value(); - if (convergence != 0) - { - int default_value = 0; - if (!(m_gameini_default.GetIfExists("Video_Stereoscopy", "StereoConvergence", &default_value) && - default_value == convergence)) - { - m_gameini_local.GetOrCreateSection("Video_Stereoscopy") - ->Set("StereoConvergence", convergence); - } - } - - SaveCheckBox(m_use_monoscopic_shadows, "Video_Stereoscopy", "StereoEFBMonoDepth"); - - bool success = m_gameini_local.Save(m_gameini_local_path.toStdString()); - - // If the resulting file is empty, delete it. Kind of a hack, but meh. - if (success && File::GetSize(m_gameini_local_path.toStdString()) == 0) - File::Delete(m_gameini_local_path.toStdString()); + for (auto* config : findChildren()) + italics(config); + for (auto* config : findChildren()) + italics(config); + for (auto* config : findChildren()) + italics(config); + for (auto* config : findChildren()) + italics(config); + for (auto* config : findChildren()) + italics(config); + for (auto* config : findChildren()) + italics(config); } diff --git a/Source/Core/DolphinQt/Config/GameConfigWidget.h b/Source/Core/DolphinQt/Config/GameConfigWidget.h index 7ad4e64925..c0eb9eb15e 100644 --- a/Source/Core/DolphinQt/Config/GameConfigWidget.h +++ b/Source/Core/DolphinQt/Config/GameConfigWidget.h @@ -7,19 +7,21 @@ #include #include - -#include "Common/IniFile.h" - namespace UICommon { class GameFile; } -class QCheckBox; -class QComboBox; +namespace Config +{ +class Layer; +} // namespace Config + +class ConfigBool; +class ConfigInteger; +class ConfigSlider; +class ConfigStringChoice; class QPushButton; -class QSlider; -class QSpinBox; class QTabWidget; class GameConfigWidget : public QWidget @@ -27,45 +29,33 @@ class GameConfigWidget : public QWidget Q_OBJECT public: explicit GameConfigWidget(const UICommon::GameFile& game); + ~GameConfigWidget(); private: void CreateWidgets(); - void ConnectWidgets(); - void LoadSettings(); - void SaveSettings(); + void SetItalics(); - void SaveCheckBox(QCheckBox* checkbox, const std::string& section, const std::string& key, - bool reverse = false); - void LoadCheckBox(QCheckBox* checkbox, const std::string& section, const std::string& key, - bool reverse = false); - - QString m_gameini_sys_path; QString m_gameini_local_path; QTabWidget* m_default_tab; QTabWidget* m_local_tab; - QCheckBox* m_enable_dual_core; - QCheckBox* m_enable_mmu; - QCheckBox* m_enable_fprf; - QCheckBox* m_sync_gpu; - QCheckBox* m_emulate_disc_speed; - QCheckBox* m_use_dsp_hle; - QCheckBox* m_use_monoscopic_shadows; - QCheckBox* m_manual_texture_sampling; + ConfigBool* m_enable_dual_core; + ConfigBool* m_enable_mmu; + ConfigBool* m_enable_fprf; + ConfigBool* m_sync_gpu; + ConfigBool* m_emulate_disc_speed; + ConfigBool* m_use_dsp_hle; + ConfigBool* m_use_monoscopic_shadows; - QPushButton* m_refresh_config; - - QComboBox* m_deterministic_dual_core; - - QSlider* m_depth_slider; - - QSpinBox* m_convergence_spin; + ConfigStringChoice* m_deterministic_dual_core; + ConfigSlider* m_depth_slider; + ConfigInteger* m_convergence_spin; const UICommon::GameFile& m_game; std::string m_game_id; - - Common::IniFile m_gameini_local; - Common::IniFile m_gameini_default; + std::unique_ptr m_layer; + std::unique_ptr m_global_layer; + int m_prev_tab_index = 0; }; diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp index 569b6856f2..c64c8fca40 100644 --- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.cpp @@ -3,11 +3,9 @@ #include "DolphinQt/Config/Graphics/AdvancedWidget.h" -#include #include #include #include -#include #include #include "Core/Config/GraphicsSettings.h" @@ -19,6 +17,7 @@ #include "DolphinQt/Config/ConfigControls/ConfigBool.h" #include "DolphinQt/Config/ConfigControls/ConfigChoice.h" #include "DolphinQt/Config/ConfigControls/ConfigInteger.h" +#include "DolphinQt/Config/GameConfigWidget.h" #include "DolphinQt/Config/Graphics/GraphicsWindow.h" #include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h" #include "DolphinQt/QtUtils/SignalBlocking.h" @@ -29,7 +28,6 @@ AdvancedWidget::AdvancedWidget(GraphicsWindow* parent) { CreateWidgets(); - LoadSettings(); ConnectWidgets(); AddDescriptions(); @@ -37,17 +35,30 @@ AdvancedWidget::AdvancedWidget(GraphicsWindow* parent) connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { OnEmulationStateChanged(state != Core::State::Uninitialized); }); - connect(m_manual_texture_sampling, &QCheckBox::toggled, [this, parent] { - SaveSettings(); - emit parent->UseFastTextureSamplingChanged(); - }); + connect(m_manual_texture_sampling, &QCheckBox::toggled, + [this, parent] { emit parent->UseFastTextureSamplingChanged(); }); OnBackendChanged(); OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance())); } +AdvancedWidget::AdvancedWidget(GameConfigWidget* parent, Config::Layer* layer) : m_game_layer(layer) +{ + CreateWidgets(); + ConnectWidgets(); + AddDescriptions(); + + connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { + OnEmulationStateChanged(state != Core::State::Uninitialized); + }); + OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()) != + Core::State::Uninitialized); +} + void AdvancedWidget::CreateWidgets() { + const bool local_edit = m_game_layer != nullptr; + auto* main_layout = new QVBoxLayout; // Performance @@ -55,17 +66,19 @@ void AdvancedWidget::CreateWidgets() auto* performance_layout = new QGridLayout(); performance_box->setLayout(performance_layout); - m_show_fps = new ConfigBool(tr("Show FPS"), Config::GFX_SHOW_FPS); - m_show_ftimes = new ConfigBool(tr("Show Frame Times"), Config::GFX_SHOW_FTIMES); - m_show_vps = new ConfigBool(tr("Show VPS"), Config::GFX_SHOW_VPS); - m_show_vtimes = new ConfigBool(tr("Show VBlank Times"), Config::GFX_SHOW_VTIMES); - m_show_graphs = new ConfigBool(tr("Show Performance Graphs"), Config::GFX_SHOW_GRAPHS); - m_show_speed = new ConfigBool(tr("Show % Speed"), Config::GFX_SHOW_SPEED); - m_show_speed_colors = new ConfigBool(tr("Show Speed Colors"), Config::GFX_SHOW_SPEED_COLORS); - m_perf_samp_window = new ConfigInteger(0, 10000, Config::GFX_PERF_SAMP_WINDOW, 100); + m_show_fps = new ConfigBool(tr("Show FPS"), Config::GFX_SHOW_FPS, m_game_layer); + m_show_ftimes = new ConfigBool(tr("Show Frame Times"), Config::GFX_SHOW_FTIMES, m_game_layer); + m_show_vps = new ConfigBool(tr("Show VPS"), Config::GFX_SHOW_VPS, m_game_layer); + m_show_vtimes = new ConfigBool(tr("Show VBlank Times"), Config::GFX_SHOW_VTIMES, m_game_layer); + m_show_graphs = + new ConfigBool(tr("Show Performance Graphs"), Config::GFX_SHOW_GRAPHS, m_game_layer); + m_show_speed = new ConfigBool(tr("Show % Speed"), Config::GFX_SHOW_SPEED, m_game_layer); + m_show_speed_colors = + new ConfigBool(tr("Show Speed Colors"), Config::GFX_SHOW_SPEED_COLORS, m_game_layer); + m_perf_samp_window = new ConfigInteger(0, 10000, Config::GFX_PERF_SAMP_WINDOW, m_game_layer, 100); m_perf_samp_window->SetTitle(tr("Performance Sample Window (ms)")); - m_log_render_time = - new ConfigBool(tr("Log Render Time to File"), Config::GFX_LOG_RENDER_TIME_TO_FILE); + m_log_render_time = new ConfigBool(tr("Log Render Time to File"), + Config::GFX_LOG_RENDER_TIME_TO_FILE, m_game_layer); performance_layout->addWidget(m_show_fps, 0, 0); performance_layout->addWidget(m_show_ftimes, 0, 1); @@ -83,14 +96,16 @@ void AdvancedWidget::CreateWidgets() auto* debugging_layout = new QGridLayout(); debugging_box->setLayout(debugging_layout); - m_enable_wireframe = new ConfigBool(tr("Enable Wireframe"), Config::GFX_ENABLE_WIREFRAME); - m_show_statistics = new ConfigBool(tr("Show Statistics"), Config::GFX_OVERLAY_STATS); - m_show_proj_statistics = - new ConfigBool(tr("Show Projection Statistics"), Config::GFX_OVERLAY_PROJ_STATS); + m_enable_wireframe = + new ConfigBool(tr("Enable Wireframe"), Config::GFX_ENABLE_WIREFRAME, m_game_layer); + m_show_statistics = + new ConfigBool(tr("Show Statistics"), Config::GFX_OVERLAY_STATS, m_game_layer); + m_show_proj_statistics = new ConfigBool(tr("Show Projection Statistics"), + Config::GFX_OVERLAY_PROJ_STATS, m_game_layer); m_enable_format_overlay = - new ConfigBool(tr("Texture Format Overlay"), Config::GFX_TEXFMT_OVERLAY_ENABLE); - m_enable_api_validation = - new ConfigBool(tr("Enable API Validation Layers"), Config::GFX_ENABLE_VALIDATION_LAYER); + new ConfigBool(tr("Texture Format Overlay"), Config::GFX_TEXFMT_OVERLAY_ENABLE, m_game_layer); + m_enable_api_validation = new ConfigBool(tr("Enable API Validation Layers"), + Config::GFX_ENABLE_VALIDATION_LAYER, m_game_layer); debugging_layout->addWidget(m_enable_wireframe, 0, 0); debugging_layout->addWidget(m_show_statistics, 0, 1); @@ -103,14 +118,25 @@ void AdvancedWidget::CreateWidgets() auto* utility_layout = new QGridLayout(); utility_box->setLayout(utility_layout); - m_load_custom_textures = new ConfigBool(tr("Load Custom Textures"), Config::GFX_HIRES_TEXTURES); - m_prefetch_custom_textures = - new ConfigBool(tr("Prefetch Custom Textures"), Config::GFX_CACHE_HIRES_TEXTURES); + m_load_custom_textures = + new ConfigBool(tr("Load Custom Textures"), Config::GFX_HIRES_TEXTURES, m_game_layer); + m_prefetch_custom_textures = new ConfigBool(tr("Prefetch Custom Textures"), + Config::GFX_CACHE_HIRES_TEXTURES, m_game_layer); + m_prefetch_custom_textures->setEnabled(m_load_custom_textures->isChecked()); m_dump_efb_target = new ConfigBool(tr("Dump EFB Target"), Config::GFX_DUMP_EFB_TARGET); m_dump_xfb_target = new ConfigBool(tr("Dump XFB Target"), Config::GFX_DUMP_XFB_TARGET); - m_disable_vram_copies = - new ConfigBool(tr("Disable EFB VRAM Copies"), Config::GFX_HACK_DISABLE_COPY_TO_VRAM); - m_enable_graphics_mods = new ToolTipCheckBox(tr("Enable Graphics Mods")); + + if (local_edit) + { + // It's hazardous to accidentally set these in a game ini. + m_dump_efb_target->setEnabled(false); + m_dump_xfb_target->setEnabled(false); + } + + m_disable_vram_copies = new ConfigBool(tr("Disable EFB VRAM Copies"), + Config::GFX_HACK_DISABLE_COPY_TO_VRAM, m_game_layer); + m_enable_graphics_mods = + new ConfigBool(tr("Enable Graphics Mods"), Config::GFX_MODS_ENABLE, m_game_layer); utility_layout->addWidget(m_load_custom_textures, 0, 0); utility_layout->addWidget(m_prefetch_custom_textures, 0, 1); @@ -128,6 +154,16 @@ void AdvancedWidget::CreateWidgets() m_dump_textures = new ConfigBool(tr("Enable"), Config::GFX_DUMP_TEXTURES); m_dump_base_textures = new ConfigBool(tr("Dump Base Textures"), Config::GFX_DUMP_BASE_TEXTURES); m_dump_mip_textures = new ConfigBool(tr("Dump Mip Maps"), Config::GFX_DUMP_MIP_TEXTURES); + m_dump_mip_textures->setEnabled(m_dump_textures->isChecked()); + m_dump_base_textures->setEnabled(m_dump_textures->isChecked()); + + if (local_edit) + { + // It's hazardous to accidentally set dumping in a game ini. + m_dump_textures->setEnabled(false); + m_dump_base_textures->setEnabled(false); + m_dump_mip_textures->setEnabled(false); + } texture_dump_layout->addWidget(m_dump_textures, 0, 0); @@ -142,18 +178,22 @@ void AdvancedWidget::CreateWidgets() m_frame_dumps_resolution_type = new ConfigChoice({tr("Window Resolution"), tr("Aspect Ratio Corrected Internal Resolution"), tr("Raw Internal Resolution")}, - Config::GFX_FRAME_DUMPS_RESOLUTION_TYPE); - m_dump_use_ffv1 = new ConfigBool(tr("Use Lossless Codec (FFV1)"), Config::GFX_USE_FFV1); - m_dump_bitrate = new ConfigInteger(0, 1000000, Config::GFX_BITRATE_KBPS, 1000); - m_png_compression_level = new ConfigInteger(0, 9, Config::GFX_PNG_COMPRESSION_LEVEL); - + Config::GFX_FRAME_DUMPS_RESOLUTION_TYPE, m_game_layer); + m_png_compression_level = + new ConfigInteger(0, 9, Config::GFX_PNG_COMPRESSION_LEVEL, m_game_layer); dump_layout->addWidget(new QLabel(tr("Resolution Type:")), 0, 0); dump_layout->addWidget(m_frame_dumps_resolution_type, 0, 1); + #if defined(HAVE_FFMPEG) + m_dump_use_ffv1 = + new ConfigBool(tr("Use Lossless Codec (FFV1)"), Config::GFX_USE_FFV1, m_game_layer); + m_dump_bitrate = new ConfigInteger(0, 1000000, Config::GFX_BITRATE_KBPS, m_game_layer, 1000); + m_dump_bitrate->setEnabled(!m_dump_use_ffv1->isChecked()); dump_layout->addWidget(m_dump_use_ffv1, 1, 0); dump_layout->addWidget(new QLabel(tr("Bitrate (kbps):")), 2, 0); dump_layout->addWidget(m_dump_bitrate, 2, 1); #endif + dump_layout->addWidget(new QLabel(tr("PNG Compression Level:")), 3, 0); m_png_compression_level->SetTitle(tr("PNG Compression Level")); dump_layout->addWidget(m_png_compression_level, 3, 1); @@ -163,14 +203,16 @@ void AdvancedWidget::CreateWidgets() auto* misc_layout = new QGridLayout(); misc_box->setLayout(misc_layout); - m_enable_cropping = new ConfigBool(tr("Crop"), Config::GFX_CROP); - m_enable_prog_scan = new ToolTipCheckBox(tr("Enable Progressive Scan")); - m_backend_multithreading = - new ConfigBool(tr("Backend Multithreading"), Config::GFX_BACKEND_MULTITHREADING); + m_enable_cropping = new ConfigBool(tr("Crop"), Config::GFX_CROP, m_game_layer); + m_enable_prog_scan = + new ConfigBool(tr("Enable Progressive Scan"), Config::SYSCONF_PROGRESSIVE_SCAN, m_game_layer); + m_backend_multithreading = new ConfigBool(tr("Backend Multithreading"), + Config::GFX_BACKEND_MULTITHREADING, m_game_layer); m_prefer_vs_for_point_line_expansion = new ConfigBool( // i18n: VS is short for vertex shaders. - tr("Prefer VS for Point/Line Expansion"), Config::GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION); - m_cpu_cull = new ConfigBool(tr("Cull Vertices on the CPU"), Config::GFX_CPU_CULL); + tr("Prefer VS for Point/Line Expansion"), Config::GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION, + m_game_layer); + m_cpu_cull = new ConfigBool(tr("Cull Vertices on the CPU"), Config::GFX_CPU_CULL, m_game_layer); misc_layout->addWidget(m_enable_cropping, 0, 0); misc_layout->addWidget(m_enable_prog_scan, 0, 1); @@ -179,7 +221,7 @@ void AdvancedWidget::CreateWidgets() misc_layout->addWidget(m_cpu_cull, 2, 0); #ifdef _WIN32 m_borderless_fullscreen = - new ConfigBool(tr("Borderless Fullscreen"), Config::GFX_BORDERLESS_FULLSCREEN); + new ConfigBool(tr("Borderless Fullscreen"), Config::GFX_BORDERLESS_FULLSCREEN, m_game_layer); misc_layout->addWidget(m_borderless_fullscreen, 2, 1); #endif @@ -189,10 +231,10 @@ void AdvancedWidget::CreateWidgets() auto* experimental_layout = new QGridLayout(); experimental_box->setLayout(experimental_layout); - m_defer_efb_access_invalidation = - new ConfigBool(tr("Defer EFB Cache Invalidation"), Config::GFX_HACK_EFB_DEFER_INVALIDATION); - m_manual_texture_sampling = - new ConfigBool(tr("Manual Texture Sampling"), Config::GFX_HACK_FAST_TEXTURE_SAMPLING, true); + m_defer_efb_access_invalidation = new ConfigBool( + tr("Defer EFB Cache Invalidation"), Config::GFX_HACK_EFB_DEFER_INVALIDATION, m_game_layer); + m_manual_texture_sampling = new ConfigBool( + tr("Manual Texture Sampling"), Config::GFX_HACK_FAST_TEXTURE_SAMPLING, m_game_layer, true); experimental_layout->addWidget(m_defer_efb_access_invalidation, 0, 0); experimental_layout->addWidget(m_manual_texture_sampling, 0, 1); @@ -211,34 +253,19 @@ void AdvancedWidget::CreateWidgets() void AdvancedWidget::ConnectWidgets() { - connect(m_load_custom_textures, &QCheckBox::toggled, this, &AdvancedWidget::SaveSettings); - connect(m_dump_use_ffv1, &QCheckBox::toggled, this, &AdvancedWidget::SaveSettings); - connect(m_enable_prog_scan, &QCheckBox::toggled, this, &AdvancedWidget::SaveSettings); - connect(m_dump_textures, &QCheckBox::toggled, this, &AdvancedWidget::SaveSettings); - connect(m_enable_graphics_mods, &QCheckBox::toggled, this, &AdvancedWidget::SaveSettings); -} + connect(m_load_custom_textures, &QCheckBox::toggled, this, + [this](bool checked) { m_prefetch_custom_textures->setEnabled(checked); }); + connect(m_dump_textures, &QCheckBox::toggled, this, [this](bool checked) { + m_dump_mip_textures->setEnabled(checked); + m_dump_base_textures->setEnabled(checked); + }); + connect(m_enable_graphics_mods, &QCheckBox::toggled, this, + [this](bool checked) { emit Settings::Instance().EnableGfxModsChanged(checked); }); -void AdvancedWidget::LoadSettings() -{ - m_prefetch_custom_textures->setEnabled(Config::Get(Config::GFX_HIRES_TEXTURES)); - m_dump_bitrate->setEnabled(!Config::Get(Config::GFX_USE_FFV1)); - - m_enable_prog_scan->setChecked(Config::Get(Config::SYSCONF_PROGRESSIVE_SCAN)); - m_dump_mip_textures->setEnabled(Config::Get(Config::GFX_DUMP_TEXTURES)); - m_dump_base_textures->setEnabled(Config::Get(Config::GFX_DUMP_TEXTURES)); - - SignalBlocking(m_enable_graphics_mods)->setChecked(Settings::Instance().GetGraphicModsEnabled()); -} - -void AdvancedWidget::SaveSettings() -{ - m_prefetch_custom_textures->setEnabled(Config::Get(Config::GFX_HIRES_TEXTURES)); - m_dump_bitrate->setEnabled(!Config::Get(Config::GFX_USE_FFV1)); - - Config::SetBase(Config::SYSCONF_PROGRESSIVE_SCAN, m_enable_prog_scan->isChecked()); - m_dump_mip_textures->setEnabled(Config::Get(Config::GFX_DUMP_TEXTURES)); - m_dump_base_textures->setEnabled(Config::Get(Config::GFX_DUMP_TEXTURES)); - Settings::Instance().SetGraphicModsEnabled(m_enable_graphics_mods->isChecked()); +#if defined(HAVE_FFMPEG) + connect(m_dump_use_ffv1, &QCheckBox::toggled, this, + [this](bool checked) { m_dump_bitrate->setEnabled(!checked); }); +#endif } void AdvancedWidget::OnBackendChanged() diff --git a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h index da7504955c..e3b3688571 100644 --- a/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/AdvancedWidget.h @@ -8,22 +8,22 @@ class ConfigBool; class ConfigChoice; class ConfigInteger; +class GameConfigWidget; class GraphicsWindow; -class QCheckBox; -class QComboBox; -class QSpinBox; -class ToolTipCheckBox; + +namespace Config +{ +class Layer; +} // namespace Config class AdvancedWidget final : public QWidget { Q_OBJECT public: explicit AdvancedWidget(GraphicsWindow* parent); + AdvancedWidget(GameConfigWidget* parent, Config::Layer* layer); private: - void LoadSettings(); - void SaveSettings(); - void CreateWidgets(); void ConnectWidgets(); void AddDescriptions(); @@ -52,7 +52,7 @@ private: ConfigBool* m_dump_xfb_target; ConfigBool* m_disable_vram_copies; ConfigBool* m_load_custom_textures; - ToolTipCheckBox* m_enable_graphics_mods; + ConfigBool* m_enable_graphics_mods; // Texture dumping ConfigBool* m_dump_textures; @@ -67,7 +67,7 @@ private: // Misc ConfigBool* m_enable_cropping; - ToolTipCheckBox* m_enable_prog_scan; + ConfigBool* m_enable_prog_scan; ConfigBool* m_backend_multithreading; ConfigBool* m_prefer_vs_for_point_line_expansion; ConfigBool* m_cpu_cull; @@ -76,4 +76,6 @@ private: // Experimental ConfigBool* m_defer_efb_access_invalidation; ConfigBool* m_manual_texture_sampling; + + Config::Layer* m_game_layer = nullptr; }; diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp index 7cf67ab39a..3fd3ec42d8 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.cpp @@ -18,6 +18,7 @@ #include "DolphinQt/Config/ConfigControls/ConfigChoice.h" #include "DolphinQt/Config/ConfigControls/ConfigRadio.h" #include "DolphinQt/Config/ConfigControls/ConfigSlider.h" +#include "DolphinQt/Config/GameConfigWidget.h" #include "DolphinQt/Config/Graphics/ColorCorrectionConfigWindow.h" #include "DolphinQt/Config/Graphics/GraphicsWindow.h" #include "DolphinQt/Config/Graphics/PostProcessingConfigWindow.h" @@ -45,6 +46,15 @@ EnhancementsWidget::EnhancementsWidget(GraphicsWindow* parent) : m_block_save(fa &EnhancementsWidget::LoadSettings); } +EnhancementsWidget::EnhancementsWidget(GameConfigWidget* parent, Config::Layer* layer) + : m_game_layer(layer) +{ + CreateWidgets(); + LoadSettings(); + ConnectWidgets(); + AddDescriptions(); +} + constexpr int TEXTURE_FILTERING_DEFAULT = 0; constexpr int TEXTURE_FILTERING_ANISO_2X = 1; constexpr int TEXTURE_FILTERING_ANISO_4X = 2; @@ -104,7 +114,7 @@ void EnhancementsWidget::CreateWidgets() } } - m_ir_combo = new ConfigChoice(resolution_options, Config::GFX_EFB_SCALE); + m_ir_combo = new ConfigChoice(resolution_options, Config::GFX_EFB_SCALE, m_game_layer); m_ir_combo->setMaxVisibleItems(visible_resolution_option_count); m_aa_combo = new ToolTipComboBox(); @@ -146,19 +156,22 @@ void EnhancementsWidget::CreateWidgets() m_pp_effect = new ToolTipComboBox(); m_configure_pp_effect = new NonDefaultQPushButton(tr("Configure")); - m_scaled_efb_copy = new ConfigBool(tr("Scaled EFB Copy"), Config::GFX_HACK_COPY_EFB_SCALED); + m_scaled_efb_copy = + new ConfigBool(tr("Scaled EFB Copy"), Config::GFX_HACK_COPY_EFB_SCALED, m_game_layer); m_per_pixel_lighting = - new ConfigBool(tr("Per-Pixel Lighting"), Config::GFX_ENABLE_PIXEL_LIGHTING); + new ConfigBool(tr("Per-Pixel Lighting"), Config::GFX_ENABLE_PIXEL_LIGHTING, m_game_layer); - m_widescreen_hack = new ConfigBool(tr("Widescreen Hack"), Config::GFX_WIDESCREEN_HACK); - m_disable_fog = new ConfigBool(tr("Disable Fog"), Config::GFX_DISABLE_FOG); + m_widescreen_hack = + new ConfigBool(tr("Widescreen Hack"), Config::GFX_WIDESCREEN_HACK, m_game_layer); + m_disable_fog = new ConfigBool(tr("Disable Fog"), Config::GFX_DISABLE_FOG, m_game_layer); m_force_24bit_color = - new ConfigBool(tr("Force 24-Bit Color"), Config::GFX_ENHANCE_FORCE_TRUE_COLOR); - m_disable_copy_filter = - new ConfigBool(tr("Disable Copy Filter"), Config::GFX_ENHANCE_DISABLE_COPY_FILTER); - m_arbitrary_mipmap_detection = new ConfigBool(tr("Arbitrary Mipmap Detection"), - Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION); - m_hdr = new ConfigBool(tr("HDR Post-Processing"), Config::GFX_ENHANCE_HDR_OUTPUT); + new ConfigBool(tr("Force 24-Bit Color"), Config::GFX_ENHANCE_FORCE_TRUE_COLOR, m_game_layer); + m_disable_copy_filter = new ConfigBool(tr("Disable Copy Filter"), + Config::GFX_ENHANCE_DISABLE_COPY_FILTER, m_game_layer); + m_arbitrary_mipmap_detection = + new ConfigBool(tr("Arbitrary Mipmap Detection"), + Config::GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION, m_game_layer); + m_hdr = new ConfigBool(tr("HDR Post-Processing"), Config::GFX_ENHANCE_HDR_OUTPUT, m_game_layer); int row = 0; enhancements_layout->addWidget(new QLabel(tr("Internal Resolution:")), row, 0); @@ -209,15 +222,16 @@ void EnhancementsWidget::CreateWidgets() m_3d_mode = new ConfigChoice({tr("Off"), tr("Side-by-Side"), tr("Top-and-Bottom"), tr("Anaglyph"), tr("HDMI 3D"), tr("Passive")}, - Config::GFX_STEREO_MODE); - m_3d_depth = new ConfigSlider(0, Config::GFX_STEREO_DEPTH_MAXIMUM, Config::GFX_STEREO_DEPTH); + Config::GFX_STEREO_MODE, m_game_layer); + m_3d_depth = + new ConfigSlider(0, Config::GFX_STEREO_DEPTH_MAXIMUM, Config::GFX_STEREO_DEPTH, m_game_layer); m_3d_convergence = new ConfigSlider(0, Config::GFX_STEREO_CONVERGENCE_MAXIMUM, - Config::GFX_STEREO_CONVERGENCE, 100); + Config::GFX_STEREO_CONVERGENCE, m_game_layer, 100); - m_3d_swap_eyes = new ConfigBool(tr("Swap Eyes"), Config::GFX_STEREO_SWAP_EYES); + m_3d_swap_eyes = new ConfigBool(tr("Swap Eyes"), Config::GFX_STEREO_SWAP_EYES, m_game_layer); - m_3d_per_eye_resolution = - new ConfigBool(tr("Use Full Resolution Per Eye"), Config::GFX_STEREO_PER_EYE_RESOLUTION_FULL); + m_3d_per_eye_resolution = new ConfigBool( + tr("Use Full Resolution Per Eye"), Config::GFX_STEREO_PER_EYE_RESOLUTION_FULL, m_game_layer); stereoscopy_layout->addWidget(new QLabel(tr("Stereoscopic 3D Mode:")), 0, 0); stereoscopy_layout->addWidget(m_3d_mode, 0, 1); diff --git a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h index 9e64d5400f..f7922ee424 100644 --- a/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/EnhancementsWidget.h @@ -10,6 +10,7 @@ class ConfigBool; class ConfigChoice; class ConfigSlider; +class GameConfigWidget; class GraphicsWindow; class QCheckBox; class QComboBox; @@ -19,11 +20,17 @@ class ToolTipComboBox; class ToolTipPushButton; enum class StereoMode : int; +namespace Config +{ +class Layer; +} // namespace Config + class EnhancementsWidget final : public QWidget { Q_OBJECT public: explicit EnhancementsWidget(GraphicsWindow* parent); + EnhancementsWidget(GameConfigWidget* parent, Config::Layer* layer); private: void LoadSettings(); @@ -60,6 +67,7 @@ private: ConfigBool* m_3d_swap_eyes; ConfigBool* m_3d_per_eye_resolution; + Config::Layer* m_game_layer = nullptr; int m_msaa_modes; bool m_block_save; }; diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp index b5f5a6b05a..bd94cde5b8 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.cpp @@ -23,6 +23,7 @@ #include "DolphinQt/Config/ConfigControls/ConfigChoice.h" #include "DolphinQt/Config/ConfigControls/ConfigInteger.h" #include "DolphinQt/Config/ConfigControls/ConfigRadio.h" +#include "DolphinQt/Config/GameConfigWidget.h" #include "DolphinQt/Config/Graphics/GraphicsWindow.h" #include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" @@ -38,7 +39,6 @@ GeneralWidget::GeneralWidget(GraphicsWindow* parent) LoadSettings(); ConnectWidgets(); AddDescriptions(); - emit BackendChanged(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND))); connect(parent, &GraphicsWindow::BackendChanged, this, &GeneralWidget::OnBackendChanged); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this](Core::State state) { @@ -47,6 +47,14 @@ GeneralWidget::GeneralWidget(GraphicsWindow* parent) OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance())); } +GeneralWidget::GeneralWidget(GameConfigWidget* parent, Config::Layer* layer) : m_game_layer(layer) +{ + CreateWidgets(); + LoadSettings(); + ConnectWidgets(); + AddDescriptions(); +} + void GeneralWidget::CreateWidgets() { auto* main_layout = new QVBoxLayout; @@ -55,33 +63,36 @@ void GeneralWidget::CreateWidgets() auto* m_video_box = new QGroupBox(tr("Basic")); m_video_layout = new QGridLayout(); - m_backend_combo = new ToolTipComboBox(); + std::vector> options; + for (auto& backend : VideoBackendBase::GetAvailableBackends()) + { + options.push_back(std::make_pair(tr(backend->GetDisplayName().c_str()), + QString::fromStdString(backend->GetName()))); + } + m_backend_combo = new ConfigStringChoice(options, Config::MAIN_GFX_BACKEND, m_game_layer); + m_previous_backend = m_backend_combo->currentIndex(); + m_aspect_combo = new ConfigChoice({tr("Auto"), tr("Force 16:9"), tr("Force 4:3"), tr("Stretch to Window"), tr("Custom"), tr("Custom (Stretch)")}, - Config::GFX_ASPECT_RATIO); + Config::GFX_ASPECT_RATIO, m_game_layer); m_custom_aspect_label = new QLabel(tr("Custom Aspect Ratio:")); m_custom_aspect_label->setHidden(true); constexpr int MAX_CUSTOM_ASPECT_RATIO_RESOLUTION = 10000; m_custom_aspect_width = new ConfigInteger(1, MAX_CUSTOM_ASPECT_RATIO_RESOLUTION, - Config::GFX_CUSTOM_ASPECT_RATIO_WIDTH); + Config::GFX_CUSTOM_ASPECT_RATIO_WIDTH, m_game_layer); m_custom_aspect_width->setEnabled(false); m_custom_aspect_width->setHidden(true); m_custom_aspect_height = new ConfigInteger(1, MAX_CUSTOM_ASPECT_RATIO_RESOLUTION, - Config::GFX_CUSTOM_ASPECT_RATIO_HEIGHT); + Config::GFX_CUSTOM_ASPECT_RATIO_HEIGHT, m_game_layer); m_custom_aspect_height->setEnabled(false); m_custom_aspect_height->setHidden(true); m_adapter_combo = new ToolTipComboBox; - m_enable_vsync = new ConfigBool(tr("V-Sync"), Config::GFX_VSYNC); - m_enable_fullscreen = new ConfigBool(tr("Start in Fullscreen"), Config::MAIN_FULLSCREEN); + m_enable_vsync = new ConfigBool(tr("V-Sync"), Config::GFX_VSYNC, m_game_layer); + m_enable_fullscreen = + new ConfigBool(tr("Start in Fullscreen"), Config::MAIN_FULLSCREEN, m_game_layer); m_video_box->setLayout(m_video_layout); - for (auto& backend : VideoBackendBase::GetAvailableBackends()) - { - m_backend_combo->addItem(tr(backend->GetDisplayName().c_str()), - QVariant(QString::fromStdString(backend->GetName()))); - } - m_video_layout->addWidget(new QLabel(tr("Backend:")), 0, 0); m_video_layout->addWidget(m_backend_combo, 0, 1, 1, -1); @@ -102,11 +113,14 @@ void GeneralWidget::CreateWidgets() auto* m_options_box = new QGroupBox(tr("Other")); auto* m_options_layout = new QGridLayout(); - m_show_ping = new ConfigBool(tr("Show NetPlay Ping"), Config::GFX_SHOW_NETPLAY_PING); - m_autoadjust_window_size = - new ConfigBool(tr("Auto-Adjust Window Size"), Config::MAIN_RENDER_WINDOW_AUTOSIZE); - m_show_messages = new ConfigBool(tr("Show NetPlay Messages"), Config::GFX_SHOW_NETPLAY_MESSAGES); - m_render_main_window = new ConfigBool(tr("Render to Main Window"), Config::MAIN_RENDER_TO_MAIN); + m_show_ping = + new ConfigBool(tr("Show NetPlay Ping"), Config::GFX_SHOW_NETPLAY_PING, m_game_layer); + m_autoadjust_window_size = new ConfigBool(tr("Auto-Adjust Window Size"), + Config::MAIN_RENDER_WINDOW_AUTOSIZE, m_game_layer); + m_show_messages = + new ConfigBool(tr("Show NetPlay Messages"), Config::GFX_SHOW_NETPLAY_MESSAGES, m_game_layer); + m_render_main_window = + new ConfigBool(tr("Render to Main Window"), Config::MAIN_RENDER_TO_MAIN, m_game_layer); m_options_box->setLayout(m_options_layout); @@ -128,13 +142,13 @@ void GeneralWidget::CreateWidgets() }}; for (size_t i = 0; i < modes.size(); i++) { - m_shader_compilation_mode[i] = - new ConfigRadioInt(tr(modes[i]), Config::GFX_SHADER_COMPILATION_MODE, static_cast(i)); + m_shader_compilation_mode[i] = new ConfigRadioInt( + tr(modes[i]), Config::GFX_SHADER_COMPILATION_MODE, static_cast(i), m_game_layer); shader_compilation_layout->addWidget(m_shader_compilation_mode[i], static_cast(i / 2), static_cast(i % 2)); } m_wait_for_shaders = new ConfigBool(tr("Compile Shaders Before Starting"), - Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING); + Config::GFX_WAIT_FOR_SHADERS_BEFORE_STARTING, m_game_layer); shader_compilation_layout->addWidget(m_wait_for_shaders); shader_compilation_box->setLayout(shader_compilation_layout); @@ -149,7 +163,7 @@ void GeneralWidget::CreateWidgets() void GeneralWidget::ConnectWidgets() { // Video Backend - connect(m_backend_combo, &QComboBox::currentIndexChanged, this, &GeneralWidget::SaveSettings); + connect(m_backend_combo, &QComboBox::currentIndexChanged, this, &GeneralWidget::BackendWarning); connect(m_adapter_combo, &QComboBox::currentIndexChanged, this, [&](int index) { g_Config.iAdapter = index; Config::SetBaseOrCurrent(Config::GFX_ADAPTER, index); @@ -168,10 +182,6 @@ void GeneralWidget::ConnectWidgets() void GeneralWidget::LoadSettings() { - // Video Backend - m_backend_combo->setCurrentIndex(m_backend_combo->findData( - QVariant(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND))))); - const bool is_custom_aspect_ratio = (Config::Get(Config::GFX_ASPECT_RATIO) == AspectMode::Custom) || (Config::Get(Config::GFX_ASPECT_RATIO) == AspectMode::CustomStretch); @@ -182,13 +192,8 @@ void GeneralWidget::LoadSettings() m_custom_aspect_height->setHidden(!is_custom_aspect_ratio); } -void GeneralWidget::SaveSettings() +void GeneralWidget::BackendWarning() { - // Video Backend - const auto current_backend = m_backend_combo->currentData().toString().toStdString(); - if (Config::Get(Config::MAIN_GFX_BACKEND) == current_backend) - return; - if (Config::GetActiveLayerForConfig(Config::MAIN_GFX_BACKEND) == Config::LayerType::Base) { auto warningMessage = VideoBackendBase::GetAvailableBackends()[m_backend_combo->currentIndex()] @@ -205,15 +210,14 @@ void GeneralWidget::SaveSettings() SetQWidgetWindowDecorations(&confirm_sw); if (confirm_sw.exec() != QMessageBox::Yes) { - m_backend_combo->setCurrentIndex(m_backend_combo->findData( - QVariant(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND))))); + m_backend_combo->setCurrentIndex(m_previous_backend); return; } } } - Config::SetBaseOrCurrent(Config::MAIN_GFX_BACKEND, current_backend); - emit BackendChanged(QString::fromStdString(current_backend)); + m_previous_backend = m_backend_combo->currentIndex(); + emit BackendChanged(m_backend_combo->currentData().toString()); } void GeneralWidget::OnEmulationStateChanged(bool running) @@ -227,7 +231,10 @@ void GeneralWidget::OnEmulationStateChanged(bool running) std::string current_backend = m_backend_combo->currentData().toString().toStdString(); if (Config::Get(Config::MAIN_GFX_BACKEND) != current_backend) + { + m_backend_combo->Load(); emit BackendChanged(QString::fromStdString(Config::Get(Config::MAIN_GFX_BACKEND))); + } } void GeneralWidget::AddDescriptions() @@ -348,8 +355,6 @@ void GeneralWidget::AddDescriptions() void GeneralWidget::OnBackendChanged(const QString& backend_name) { - m_backend_combo->setCurrentIndex(m_backend_combo->findData(QVariant(backend_name))); - const QSignalBlocker blocker(m_adapter_combo); m_adapter_combo->clear(); diff --git a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h index 4f908bfa30..5b4bf36441 100644 --- a/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/GeneralWidget.h @@ -11,6 +11,8 @@ class ConfigBool; class ConfigChoice; class ConfigInteger; class ConfigRadioInt; +class ConfigStringChoice; +class GameConfigWidget; class GraphicsWindow; class QCheckBox; class QComboBox; @@ -19,17 +21,24 @@ class QRadioButton; class QGridLayout; class ToolTipComboBox; +namespace Config +{ +class Layer; +} // namespace Config + class GeneralWidget final : public QWidget { Q_OBJECT public: explicit GeneralWidget(GraphicsWindow* parent); + GeneralWidget(GameConfigWidget* parent, Config::Layer* layer); + signals: void BackendChanged(const QString& backend); private: void LoadSettings(); - void SaveSettings(); + void BackendWarning(); void CreateWidgets(); void ConnectWidgets(); @@ -40,7 +49,7 @@ private: // Video QGridLayout* m_video_layout; - ToolTipComboBox* m_backend_combo; + ConfigStringChoice* m_backend_combo; ToolTipComboBox* m_adapter_combo; ConfigChoice* m_aspect_combo; QLabel* m_custom_aspect_label; @@ -56,4 +65,6 @@ private: ConfigBool* m_render_main_window; std::array m_shader_compilation_mode{}; ConfigBool* m_wait_for_shaders; + int m_previous_backend = 0; + Config::Layer* m_game_layer = nullptr; }; diff --git a/Source/Core/DolphinQt/Config/Graphics/HacksWidget.cpp b/Source/Core/DolphinQt/Config/Graphics/HacksWidget.cpp index 19712e38f8..49a1c50b68 100644 --- a/Source/Core/DolphinQt/Config/Graphics/HacksWidget.cpp +++ b/Source/Core/DolphinQt/Config/Graphics/HacksWidget.cpp @@ -15,6 +15,7 @@ #include "DolphinQt/Config/ConfigControls/ConfigBool.h" #include "DolphinQt/Config/ConfigControls/ConfigSlider.h" +#include "DolphinQt/Config/GameConfigWidget.h" #include "DolphinQt/Config/Graphics/GraphicsWindow.h" #include "DolphinQt/Config/ToolTipControls/ToolTipSlider.h" #include "DolphinQt/Settings.h" @@ -37,6 +38,14 @@ HacksWidget::HacksWidget(GraphicsWindow* parent) }); } +HacksWidget::HacksWidget(GameConfigWidget* parent, Config::Layer* layer) : m_game_layer(layer) +{ + CreateWidgets(); + LoadSettings(); + ConnectWidgets(); + AddDescriptions(); +} + void HacksWidget::CreateWidgets() { auto* main_layout = new QVBoxLayout; @@ -45,14 +54,14 @@ void HacksWidget::CreateWidgets() auto* efb_box = new QGroupBox(tr("Embedded Frame Buffer (EFB)")); auto* efb_layout = new QGridLayout(); efb_box->setLayout(efb_layout); - m_skip_efb_cpu = - new ConfigBool(tr("Skip EFB Access from CPU"), Config::GFX_HACK_EFB_ACCESS_ENABLE, true); - m_ignore_format_changes = new ConfigBool(tr("Ignore Format Changes"), - Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES, true); - m_store_efb_copies = - new ConfigBool(tr("Store EFB Copies to Texture Only"), Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM); - m_defer_efb_copies = - new ConfigBool(tr("Defer EFB Copies to RAM"), Config::GFX_HACK_DEFER_EFB_COPIES); + m_skip_efb_cpu = new ConfigBool(tr("Skip EFB Access from CPU"), + Config::GFX_HACK_EFB_ACCESS_ENABLE, m_game_layer, true); + m_ignore_format_changes = new ConfigBool( + tr("Ignore Format Changes"), Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES, m_game_layer, true); + m_store_efb_copies = new ConfigBool(tr("Store EFB Copies to Texture Only"), + Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, m_game_layer); + m_defer_efb_copies = new ConfigBool(tr("Defer EFB Copies to RAM"), + Config::GFX_HACK_DEFER_EFB_COPIES, m_game_layer); efb_layout->addWidget(m_skip_efb_cpu, 0, 0); efb_layout->addWidget(m_ignore_format_changes, 0, 1); @@ -69,8 +78,8 @@ void HacksWidget::CreateWidgets() m_accuracy->setMaximum(2); m_accuracy->setPageStep(1); m_accuracy->setTickPosition(QSlider::TicksBelow); - m_gpu_texture_decoding = - new ConfigBool(tr("GPU Texture Decoding"), Config::GFX_ENABLE_GPU_TEXTURE_DECODING); + m_gpu_texture_decoding = new ConfigBool(tr("GPU Texture Decoding"), + Config::GFX_ENABLE_GPU_TEXTURE_DECODING, m_game_layer); auto* safe_label = new QLabel(tr("Safe")); safe_label->setAlignment(Qt::AlignRight); @@ -88,11 +97,12 @@ void HacksWidget::CreateWidgets() auto* xfb_layout = new QVBoxLayout(); xfb_box->setLayout(xfb_layout); - m_store_xfb_copies = - new ConfigBool(tr("Store XFB Copies to Texture Only"), Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM); - m_immediate_xfb = new ConfigBool(tr("Immediately Present XFB"), Config::GFX_HACK_IMMEDIATE_XFB); - m_skip_duplicate_xfbs = - new ConfigBool(tr("Skip Presenting Duplicate Frames"), Config::GFX_HACK_SKIP_DUPLICATE_XFBS); + m_store_xfb_copies = new ConfigBool(tr("Store XFB Copies to Texture Only"), + Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM, m_game_layer); + m_immediate_xfb = + new ConfigBool(tr("Immediately Present XFB"), Config::GFX_HACK_IMMEDIATE_XFB, m_game_layer); + m_skip_duplicate_xfbs = new ConfigBool(tr("Skip Presenting Duplicate Frames"), + Config::GFX_HACK_SKIP_DUPLICATE_XFBS, m_game_layer); xfb_layout->addWidget(m_store_xfb_copies); xfb_layout->addWidget(m_immediate_xfb); @@ -104,13 +114,14 @@ void HacksWidget::CreateWidgets() other_box->setLayout(other_layout); m_fast_depth_calculation = - new ConfigBool(tr("Fast Depth Calculation"), Config::GFX_FAST_DEPTH_CALC); + new ConfigBool(tr("Fast Depth Calculation"), Config::GFX_FAST_DEPTH_CALC, m_game_layer); m_disable_bounding_box = - new ConfigBool(tr("Disable Bounding Box"), Config::GFX_HACK_BBOX_ENABLE, true); - m_vertex_rounding = new ConfigBool(tr("Vertex Rounding"), Config::GFX_HACK_VERTEX_ROUNDING); - m_save_texture_cache_state = - new ConfigBool(tr("Save Texture Cache to State"), Config::GFX_SAVE_TEXTURE_CACHE_TO_STATE); - m_vi_skip = new ConfigBool(tr("VBI Skip"), Config::GFX_HACK_VI_SKIP); + new ConfigBool(tr("Disable Bounding Box"), Config::GFX_HACK_BBOX_ENABLE, m_game_layer, true); + m_vertex_rounding = + new ConfigBool(tr("Vertex Rounding"), Config::GFX_HACK_VERTEX_ROUNDING, m_game_layer); + m_save_texture_cache_state = new ConfigBool( + tr("Save Texture Cache to State"), Config::GFX_SAVE_TEXTURE_CACHE_TO_STATE, m_game_layer); + m_vi_skip = new ConfigBool(tr("VBI Skip"), Config::GFX_HACK_VI_SKIP, m_game_layer); other_layout->addWidget(m_fast_depth_calculation, 0, 0); other_layout->addWidget(m_disable_bounding_box, 0, 1); diff --git a/Source/Core/DolphinQt/Config/Graphics/HacksWidget.h b/Source/Core/DolphinQt/Config/Graphics/HacksWidget.h index 995a901ad4..391570278c 100644 --- a/Source/Core/DolphinQt/Config/Graphics/HacksWidget.h +++ b/Source/Core/DolphinQt/Config/Graphics/HacksWidget.h @@ -6,15 +6,22 @@ #include class ConfigBool; +class GameConfigWidget; class GraphicsWindow; class QLabel; class ToolTipSlider; +namespace Config +{ +class Layer; +} // namespace Config + class HacksWidget final : public QWidget { Q_OBJECT public: explicit HacksWidget(GraphicsWindow* parent); + HacksWidget(GameConfigWidget* parent, Config::Layer* layer); private: void LoadSettings(); @@ -45,6 +52,8 @@ private: ConfigBool* m_vi_skip; ConfigBool* m_save_texture_cache_state; + Config::Layer* m_game_layer = nullptr; + void CreateWidgets(); void ConnectWidgets(); void AddDescriptions(); diff --git a/Source/Core/DolphinQt/GameList/GameList.cpp b/Source/Core/DolphinQt/GameList/GameList.cpp index 64e9ae6774..6c276ec97b 100644 --- a/Source/Core/DolphinQt/GameList/GameList.cpp +++ b/Source/Core/DolphinQt/GameList/GameList.cpp @@ -546,13 +546,13 @@ void GameList::OpenProperties() return; PropertiesDialog* properties = new PropertiesDialog(this, *game); - // Since the properties dialog locks the game file, it's important to free it as soon as it's - // closed so that the file can be moved or deleted. - properties->setAttribute(Qt::WA_DeleteOnClose, true); connect(properties, &PropertiesDialog::OpenGeneralSettings, this, &GameList::OpenGeneralSettings); connect(properties, &PropertiesDialog::OpenGraphicsSettings, this, &GameList::OpenGraphicsSettings); + connect(properties, &PropertiesDialog::finished, this, + [properties]() { properties->deleteLater(); }); + #ifdef USE_RETRO_ACHIEVEMENTS connect(properties, &PropertiesDialog::OpenAchievementSettings, this, &GameList::OpenAchievementSettings);