summaryrefslogtreecommitdiff
path: root/src/yuzu/configuration
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/configuration')
-rw-r--r--src/yuzu/configuration/config.cpp336
-rw-r--r--src/yuzu/configuration/config.h27
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp76
-rw-r--r--src/yuzu/configuration/configuration_shared.h36
-rw-r--r--src/yuzu/configuration/configure_audio.cpp82
-rw-r--r--src/yuzu/configuration/configure_audio.h2
-rw-r--r--src/yuzu/configuration/configure_audio.ui50
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp2
-rw-r--r--src/yuzu/configuration/configure_general.cpp78
-rw-r--r--src/yuzu/configuration/configure_general.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp156
-rw-r--r--src/yuzu/configuration/configure_graphics.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.ui36
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp106
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h2
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp140
-rw-r--r--src/yuzu/configuration/configure_per_game.h51
-rw-r--r--src/yuzu/configuration/configure_per_game.ui350
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.cpp (renamed from src/yuzu/configuration/configure_per_general.cpp)95
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.h (renamed from src/yuzu/configuration/configure_per_general.h)16
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.ui38
-rw-r--r--src/yuzu/configuration/configure_per_general.ui276
-rw-r--r--src/yuzu/configuration/configure_system.cpp190
-rw-r--r--src/yuzu/configuration/configure_system.h2
24 files changed, 1558 insertions, 593 deletions
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 5e0d0e7af..1b2b1b2bb 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -13,17 +13,20 @@
#include "input_common/udp/client.h"
#include "yuzu/configuration/config.h"
-Config::Config() {
+Config::Config(const std::string& config_file, bool is_global) {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
- qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + "qt-config.ini";
+ qt_config_loc = FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + config_file;
FileUtil::CreateFullPath(qt_config_loc);
qt_config =
std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
+ global = is_global;
Reload();
}
Config::~Config() {
- Save();
+ if (global) {
+ Save();
+ }
}
const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
@@ -402,16 +405,19 @@ void Config::ApplyDefaultProfileIfInputInvalid() {
void Config::ReadAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
- Settings::values.sink_id = ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto"))
- .toString()
- .toStdString();
- Settings::values.enable_audio_stretching =
- ReadSetting(QStringLiteral("enable_audio_stretching"), true).toBool();
- Settings::values.audio_device_id =
- ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto"))
- .toString()
- .toStdString();
- Settings::values.volume = ReadSetting(QStringLiteral("volume"), 1).toFloat();
+ if (global) {
+ Settings::values.sink_id =
+ ReadSetting(QStringLiteral("output_engine"), QStringLiteral("auto"))
+ .toString()
+ .toStdString();
+ Settings::values.audio_device_id =
+ ReadSetting(QStringLiteral("output_device"), QStringLiteral("auto"))
+ .toString()
+ .toStdString();
+ }
+ ReadSettingGlobal(Settings::values.enable_audio_stretching,
+ QStringLiteral("enable_audio_stretching"), true);
+ ReadSettingGlobal(Settings::values.volume, QStringLiteral("volume"), 1);
qt_config->endGroup();
}
@@ -440,6 +446,8 @@ void Config::ReadControlValues() {
.toInt());
Settings::values.udp_pad_index =
static_cast<u8>(ReadSetting(QStringLiteral("udp_pad_index"), 0).toUInt());
+ Settings::values.use_docked_mode =
+ ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
qt_config->endGroup();
}
@@ -447,7 +455,7 @@ void Config::ReadControlValues() {
void Config::ReadCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
- Settings::values.use_multi_core = ReadSetting(QStringLiteral("use_multi_core"), false).toBool();
+ ReadSettingGlobal(Settings::values.use_multi_core, QStringLiteral("use_multi_core"), false);
qt_config->endGroup();
}
@@ -628,32 +636,28 @@ void Config::ReadPathValues() {
void Config::ReadRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer"));
- Settings::values.renderer_backend =
- static_cast<Settings::RendererBackend>(ReadSetting(QStringLiteral("backend"), 0).toInt());
- Settings::values.renderer_debug = ReadSetting(QStringLiteral("debug"), false).toBool();
- Settings::values.vulkan_device = ReadSetting(QStringLiteral("vulkan_device"), 0).toInt();
- Settings::values.aspect_ratio = ReadSetting(QStringLiteral("aspect_ratio"), 0).toInt();
- Settings::values.max_anisotropy = ReadSetting(QStringLiteral("max_anisotropy"), 0).toInt();
- Settings::values.use_frame_limit =
- ReadSetting(QStringLiteral("use_frame_limit"), true).toBool();
- Settings::values.frame_limit = ReadSetting(QStringLiteral("frame_limit"), 100).toUInt();
- Settings::values.use_disk_shader_cache =
- ReadSetting(QStringLiteral("use_disk_shader_cache"), true).toBool();
- const int gpu_accuracy_level = ReadSetting(QStringLiteral("gpu_accuracy"), 0).toInt();
- Settings::values.gpu_accuracy = static_cast<Settings::GPUAccuracy>(gpu_accuracy_level);
- Settings::values.use_asynchronous_gpu_emulation =
- ReadSetting(QStringLiteral("use_asynchronous_gpu_emulation"), false).toBool();
- Settings::values.use_vsync = ReadSetting(QStringLiteral("use_vsync"), true).toBool();
- Settings::values.use_assembly_shaders =
- ReadSetting(QStringLiteral("use_assembly_shaders"), false).toBool();
- Settings::values.use_fast_gpu_time =
- ReadSetting(QStringLiteral("use_fast_gpu_time"), true).toBool();
- Settings::values.force_30fps_mode =
- ReadSetting(QStringLiteral("force_30fps_mode"), false).toBool();
-
- Settings::values.bg_red = ReadSetting(QStringLiteral("bg_red"), 0.0).toFloat();
- Settings::values.bg_green = ReadSetting(QStringLiteral("bg_green"), 0.0).toFloat();
- Settings::values.bg_blue = ReadSetting(QStringLiteral("bg_blue"), 0.0).toFloat();
+ ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
+ ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
+ ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
+ ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
+ ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
+ ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
+ ReadSettingGlobal(Settings::values.frame_limit, QStringLiteral("frame_limit"), 100);
+ ReadSettingGlobal(Settings::values.use_disk_shader_cache,
+ QStringLiteral("use_disk_shader_cache"), true);
+ ReadSettingGlobal(Settings::values.gpu_accuracy, QStringLiteral("gpu_accuracy"), 0);
+ ReadSettingGlobal(Settings::values.use_asynchronous_gpu_emulation,
+ QStringLiteral("use_asynchronous_gpu_emulation"), false);
+ ReadSettingGlobal(Settings::values.use_vsync, QStringLiteral("use_vsync"), true);
+ ReadSettingGlobal(Settings::values.use_assembly_shaders, QStringLiteral("use_assembly_shaders"),
+ false);
+ ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
+ true);
+ ReadSettingGlobal(Settings::values.force_30fps_mode, QStringLiteral("force_30fps_mode"), false);
+
+ ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"), 0.0);
+ ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"), 0.0);
+ ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"), 0.0);
qt_config->endGroup();
}
@@ -682,35 +686,45 @@ void Config::ReadShortcutValues() {
void Config::ReadSystemValues() {
qt_config->beginGroup(QStringLiteral("System"));
- Settings::values.use_docked_mode =
- ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
-
- Settings::values.current_user = std::clamp<int>(
- ReadSetting(QStringLiteral("current_user"), 0).toInt(), 0, Service::Account::MAX_USERS - 1);
+ ReadSettingGlobal(Settings::values.current_user, QStringLiteral("current_user"), 0);
+ Settings::values.current_user =
+ std::clamp<int>(Settings::values.current_user, 0, Service::Account::MAX_USERS - 1);
- Settings::values.language_index = ReadSetting(QStringLiteral("language_index"), 1).toInt();
+ ReadSettingGlobal(Settings::values.language_index, QStringLiteral("language_index"), 1);
- Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt();
+ ReadSettingGlobal(Settings::values.region_index, QStringLiteral("region_index"), 1);
- Settings::values.time_zone_index = ReadSetting(QStringLiteral("time_zone_index"), 0).toInt();
+ ReadSettingGlobal(Settings::values.time_zone_index, QStringLiteral("time_zone_index"), 0);
- const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool();
- if (rng_seed_enabled) {
- Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong();
- } else {
- Settings::values.rng_seed = std::nullopt;
+ bool rng_seed_enabled;
+ ReadSettingGlobal(rng_seed_enabled, QStringLiteral("rng_seed_enabled"), false);
+ bool rng_seed_global =
+ global || qt_config->value(QStringLiteral("rng_seed/use_global"), true).toBool();
+ Settings::values.rng_seed.SetGlobal(rng_seed_global);
+ if (global || !rng_seed_global) {
+ if (rng_seed_enabled) {
+ Settings::values.rng_seed.SetValue(
+ ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong());
+ } else {
+ Settings::values.rng_seed.SetValue(std::nullopt);
+ }
}
- const auto custom_rtc_enabled =
- ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool();
- if (custom_rtc_enabled) {
- Settings::values.custom_rtc =
- std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong());
- } else {
- Settings::values.custom_rtc = std::nullopt;
+ bool custom_rtc_enabled;
+ ReadSettingGlobal(custom_rtc_enabled, QStringLiteral("custom_rtc_enabled"), false);
+ bool custom_rtc_global =
+ global || qt_config->value(QStringLiteral("custom_rtc/use_global"), true).toBool();
+ Settings::values.custom_rtc.SetGlobal(custom_rtc_global);
+ if (global || !custom_rtc_global) {
+ if (custom_rtc_enabled) {
+ Settings::values.custom_rtc.SetValue(
+ std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong()));
+ } else {
+ Settings::values.custom_rtc.SetValue(std::nullopt);
+ }
}
- Settings::values.sound_index = ReadSetting(QStringLiteral("sound_index"), 1).toInt();
+ ReadSettingGlobal(Settings::values.sound_index, QStringLiteral("sound_index"), 1);
qt_config->endGroup();
}
@@ -804,18 +818,20 @@ void Config::ReadWebServiceValues() {
}
void Config::ReadValues() {
- ReadControlValues();
+ if (global) {
+ ReadControlValues();
+ ReadDataStorageValues();
+ ReadDebuggingValues();
+ ReadDisabledAddOnValues();
+ ReadServiceValues();
+ ReadUIValues();
+ ReadWebServiceValues();
+ ReadMiscellaneousValues();
+ }
ReadCoreValues();
ReadRendererValues();
ReadAudioValues();
- ReadDataStorageValues();
ReadSystemValues();
- ReadMiscellaneousValues();
- ReadDebuggingValues();
- ReadWebServiceValues();
- ReadServiceValues();
- ReadDisabledAddOnValues();
- ReadUIValues();
}
void Config::SavePlayerValues() {
@@ -902,30 +918,35 @@ void Config::SaveTouchscreenValues() {
}
void Config::SaveValues() {
- SaveControlValues();
+ if (global) {
+ SaveControlValues();
+ SaveDataStorageValues();
+ SaveDebuggingValues();
+ SaveDisabledAddOnValues();
+ SaveServiceValues();
+ SaveUIValues();
+ SaveWebServiceValues();
+ SaveMiscellaneousValues();
+ }
SaveCoreValues();
SaveRendererValues();
SaveAudioValues();
- SaveDataStorageValues();
SaveSystemValues();
- SaveMiscellaneousValues();
- SaveDebuggingValues();
- SaveWebServiceValues();
- SaveServiceValues();
- SaveDisabledAddOnValues();
- SaveUIValues();
}
void Config::SaveAudioValues() {
qt_config->beginGroup(QStringLiteral("Audio"));
- WriteSetting(QStringLiteral("output_engine"), QString::fromStdString(Settings::values.sink_id),
- QStringLiteral("auto"));
- WriteSetting(QStringLiteral("enable_audio_stretching"),
- Settings::values.enable_audio_stretching, true);
- WriteSetting(QStringLiteral("output_device"),
- QString::fromStdString(Settings::values.audio_device_id), QStringLiteral("auto"));
- WriteSetting(QStringLiteral("volume"), Settings::values.volume, 1.0f);
+ if (global) {
+ WriteSetting(QStringLiteral("output_engine"),
+ QString::fromStdString(Settings::values.sink_id), QStringLiteral("auto"));
+ WriteSetting(QStringLiteral("output_device"),
+ QString::fromStdString(Settings::values.audio_device_id),
+ QStringLiteral("auto"));
+ }
+ WriteSettingGlobal(QStringLiteral("enable_audio_stretching"),
+ Settings::values.enable_audio_stretching, true);
+ WriteSettingGlobal(QStringLiteral("volume"), Settings::values.volume, 1.0f);
qt_config->endGroup();
}
@@ -948,6 +969,7 @@ void Config::SaveControlValues() {
WriteSetting(QStringLiteral("udp_input_port"), Settings::values.udp_input_port,
InputCommon::CemuhookUDP::DEFAULT_PORT);
WriteSetting(QStringLiteral("udp_pad_index"), Settings::values.udp_pad_index, 0);
+ WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
qt_config->endGroup();
}
@@ -955,7 +977,7 @@ void Config::SaveControlValues() {
void Config::SaveCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
- WriteSetting(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, false);
+ WriteSettingGlobal(QStringLiteral("use_multi_core"), Settings::values.use_multi_core, false);
qt_config->endGroup();
}
@@ -1078,29 +1100,34 @@ void Config::SavePathValues() {
void Config::SaveRendererValues() {
qt_config->beginGroup(QStringLiteral("Renderer"));
- WriteSetting(QStringLiteral("backend"), static_cast<int>(Settings::values.renderer_backend), 0);
+ WriteSettingGlobal(QStringLiteral("backend"),
+ static_cast<int>(Settings::values.renderer_backend.GetValue(global)),
+ Settings::values.renderer_backend.UsingGlobal(), 0);
WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
- WriteSetting(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
- WriteSetting(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
- WriteSetting(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
- WriteSetting(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
- WriteSetting(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100);
- WriteSetting(QStringLiteral("use_disk_shader_cache"), Settings::values.use_disk_shader_cache,
- true);
- WriteSetting(QStringLiteral("gpu_accuracy"), static_cast<int>(Settings::values.gpu_accuracy),
- 0);
- WriteSetting(QStringLiteral("use_asynchronous_gpu_emulation"),
- Settings::values.use_asynchronous_gpu_emulation, false);
- WriteSetting(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
- WriteSetting(QStringLiteral("use_assembly_shaders"), Settings::values.use_assembly_shaders,
- false);
- WriteSetting(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time, true);
- WriteSetting(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode, false);
+ WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
+ WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
+ WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
+ WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
+ WriteSettingGlobal(QStringLiteral("frame_limit"), Settings::values.frame_limit, 100);
+ WriteSettingGlobal(QStringLiteral("use_disk_shader_cache"),
+ Settings::values.use_disk_shader_cache, true);
+ WriteSettingGlobal(QStringLiteral("gpu_accuracy"),
+ static_cast<int>(Settings::values.gpu_accuracy.GetValue(global)),
+ Settings::values.gpu_accuracy.UsingGlobal(), 0);
+ WriteSettingGlobal(QStringLiteral("use_asynchronous_gpu_emulation"),
+ Settings::values.use_asynchronous_gpu_emulation, false);
+ WriteSettingGlobal(QStringLiteral("use_vsync"), Settings::values.use_vsync, true);
+ WriteSettingGlobal(QStringLiteral("use_assembly_shaders"),
+ Settings::values.use_assembly_shaders, false);
+ WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
+ true);
+ WriteSettingGlobal(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode,
+ false);
// Cast to double because Qt's written float values are not human-readable
- WriteSetting(QStringLiteral("bg_red"), static_cast<double>(Settings::values.bg_red), 0.0);
- WriteSetting(QStringLiteral("bg_green"), static_cast<double>(Settings::values.bg_green), 0.0);
- WriteSetting(QStringLiteral("bg_blue"), static_cast<double>(Settings::values.bg_blue), 0.0);
+ WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red, 0.0);
+ WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green, 0.0);
+ WriteSettingGlobal(QStringLiteral("bg_blue"), Settings::values.bg_blue, 0.0);
qt_config->endGroup();
}
@@ -1128,23 +1155,28 @@ void Config::SaveShortcutValues() {
void Config::SaveSystemValues() {
qt_config->beginGroup(QStringLiteral("System"));
- WriteSetting(QStringLiteral("use_docked_mode"), Settings::values.use_docked_mode, false);
WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0);
- WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1);
- WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1);
- WriteSetting(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0);
-
- WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false);
- WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0);
-
- WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(),
- false);
- WriteSetting(QStringLiteral("custom_rtc"),
- QVariant::fromValue<long long>(
- Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()),
- 0);
-
- WriteSetting(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
+ WriteSettingGlobal(QStringLiteral("language_index"), Settings::values.language_index, 1);
+ WriteSettingGlobal(QStringLiteral("region_index"), Settings::values.region_index, 1);
+ WriteSettingGlobal(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0);
+
+ WriteSettingGlobal(QStringLiteral("rng_seed_enabled"),
+ Settings::values.rng_seed.GetValue(global).has_value(),
+ Settings::values.rng_seed.UsingGlobal(), false);
+ WriteSettingGlobal(QStringLiteral("rng_seed"),
+ Settings::values.rng_seed.GetValue(global).value_or(0),
+ Settings::values.rng_seed.UsingGlobal(), 0);
+
+ WriteSettingGlobal(QStringLiteral("custom_rtc_enabled"),
+ Settings::values.custom_rtc.GetValue(global).has_value(),
+ Settings::values.custom_rtc.UsingGlobal(), false);
+ WriteSettingGlobal(
+ QStringLiteral("custom_rtc"),
+ QVariant::fromValue<long long>(
+ Settings::values.custom_rtc.GetValue(global).value_or(std::chrono::seconds{}).count()),
+ Settings::values.custom_rtc.UsingGlobal(), 0);
+
+ WriteSettingGlobal(QStringLiteral("sound_index"), Settings::values.sound_index, 1);
qt_config->endGroup();
}
@@ -1236,6 +1268,34 @@ QVariant Config::ReadSetting(const QString& name, const QVariant& default_value)
return result;
}
+template <typename Type>
+void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name) {
+ const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
+ setting.SetGlobal(use_global);
+ if (global || !use_global) {
+ setting.SetValue(ReadSetting(name).value<Type>());
+ }
+}
+
+template <typename Type>
+void Config::ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
+ const QVariant& default_value) {
+ const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
+ setting.SetGlobal(use_global);
+ if (global || !use_global) {
+ setting.SetValue(ReadSetting(name, default_value).value<Type>());
+ }
+}
+
+template <typename Type>
+void Config::ReadSettingGlobal(Type& setting, const QString& name,
+ const QVariant& default_value) const {
+ const bool use_global = qt_config->value(name + QStringLiteral("/use_global"), true).toBool();
+ if (global || !use_global) {
+ setting = ReadSetting(name, default_value).value<Type>();
+ }
+}
+
void Config::WriteSetting(const QString& name, const QVariant& value) {
qt_config->setValue(name, value);
}
@@ -1246,6 +1306,40 @@ void Config::WriteSetting(const QString& name, const QVariant& value,
qt_config->setValue(name, value);
}
+template <typename Type>
+void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting) {
+ if (!global) {
+ qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
+ }
+ if (global || !setting.UsingGlobal()) {
+ qt_config->setValue(name, setting.GetValue(global));
+ }
+}
+
+template <typename Type>
+void Config::WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
+ const QVariant& default_value) {
+ if (!global) {
+ qt_config->setValue(name + QStringLiteral("/use_global"), setting.UsingGlobal());
+ }
+ if (global || !setting.UsingGlobal()) {
+ qt_config->setValue(name + QStringLiteral("/default"),
+ setting.GetValue(global) == default_value.value<Type>());
+ qt_config->setValue(name, setting.GetValue(global));
+ }
+}
+
+void Config::WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
+ const QVariant& default_value) {
+ if (!global) {
+ qt_config->setValue(name + QStringLiteral("/use_global"), use_global);
+ }
+ if (global || !use_global) {
+ qt_config->setValue(name + QStringLiteral("/default"), value == default_value);
+ qt_config->setValue(name, value);
+ }
+}
+
void Config::Reload() {
ReadValues();
// To apply default value changes
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 09316382c..681f0bca5 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -7,6 +7,7 @@
#include <array>
#include <memory>
#include <string>
+#include <QMetaType>
#include <QVariant>
#include "core/settings.h"
#include "yuzu/uisettings.h"
@@ -15,7 +16,7 @@ class QSettings;
class Config {
public:
- Config();
+ explicit Config(const std::string& config_loc = "qt-config.ini", bool is_global = true);
~Config();
void Reload();
@@ -82,9 +83,33 @@ private:
QVariant ReadSetting(const QString& name) const;
QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
+ // Templated ReadSettingGlobal functions will also look for the use_global setting and set
+ // both the value and the global state properly
+ template <typename Type>
+ void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name);
+ template <typename Type>
+ void ReadSettingGlobal(Settings::Setting<Type>& setting, const QString& name,
+ const QVariant& default_value);
+ template <typename Type>
+ void ReadSettingGlobal(Type& setting, const QString& name, const QVariant& default_value) const;
+ // Templated WriteSettingGlobal functions will also write the global state if needed and will
+ // skip writing the actual setting if it defers to the global value
void WriteSetting(const QString& name, const QVariant& value);
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
+ template <typename Type>
+ void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting);
+ template <typename Type>
+ void WriteSettingGlobal(const QString& name, const Settings::Setting<Type>& setting,
+ const QVariant& default_value);
+ void WriteSettingGlobal(const QString& name, const QVariant& value, bool use_global,
+ const QVariant& default_value);
std::unique_ptr<QSettings> qt_config;
std::string qt_config_loc;
+
+ bool global;
};
+
+// These metatype declarations cannot be in core/settings.h because core is devoid of QT
+Q_DECLARE_METATYPE(Settings::RendererBackend);
+Q_DECLARE_METATYPE(Settings::GPUAccuracy);
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp
new file mode 100644
index 000000000..bb47c3933
--- /dev/null
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -0,0 +1,76 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QCheckBox>
+#include <QComboBox>
+#include "core/settings.h"
+#include "yuzu/configuration/configuration_shared.h"
+#include "yuzu/configuration/configure_per_game.h"
+
+void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
+ const QCheckBox* checkbox) {
+ if (checkbox->checkState() == Qt::PartiallyChecked) {
+ setting->SetGlobal(true);
+ } else {
+ setting->SetGlobal(false);
+ setting->SetValue(checkbox->checkState() == Qt::Checked);
+ }
+}
+
+void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting,
+ const QComboBox* combobox) {
+ if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ setting->SetGlobal(true);
+ } else {
+ setting->SetGlobal(false);
+ setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET);
+ }
+}
+
+void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
+ const QComboBox* combobox) {
+ if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ setting->SetGlobal(true);
+ } else {
+ setting->SetGlobal(false);
+ setting->SetValue(static_cast<Settings::RendererBackend>(
+ combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
+ }
+}
+
+void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
+ const Settings::Setting<bool>* setting) {
+ if (setting->UsingGlobal()) {
+ checkbox->setCheckState(Qt::PartiallyChecked);
+ } else {
+ checkbox->setCheckState(setting->GetValue() ? Qt::Checked : Qt::Unchecked);
+ }
+}
+
+void ConfigurationShared::SetPerGameSetting(QComboBox* combobox,
+ const Settings::Setting<int>* setting) {
+ combobox->setCurrentIndex(setting->UsingGlobal()
+ ? ConfigurationShared::USE_GLOBAL_INDEX
+ : setting->GetValue() + ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+void ConfigurationShared::SetPerGameSetting(
+ QComboBox* combobox, const Settings::Setting<Settings::RendererBackend>* setting) {
+ combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
+ : static_cast<int>(setting->GetValue()) +
+ ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+void ConfigurationShared::SetPerGameSetting(
+ QComboBox* combobox, const Settings::Setting<Settings::GPUAccuracy>* setting) {
+ combobox->setCurrentIndex(setting->UsingGlobal() ? ConfigurationShared::USE_GLOBAL_INDEX
+ : static_cast<int>(setting->GetValue()) +
+ ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+void ConfigurationShared::InsertGlobalItem(QComboBox* combobox) {
+ const QString use_global_text = ConfigurePerGame::tr("Use global configuration");
+ combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text);
+ combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX);
+}
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
new file mode 100644
index 000000000..b11b1b950
--- /dev/null
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -0,0 +1,36 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <QCheckBox>
+#include <QComboBox>
+#include <QString>
+#include "core/settings.h"
+
+namespace ConfigurationShared {
+
+constexpr int USE_GLOBAL_INDEX = 0;
+constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
+constexpr int USE_GLOBAL_OFFSET = 2;
+
+// Global-aware apply and set functions
+
+void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox);
+void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox);
+void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
+ const QComboBox* combobox);
+void ApplyPerGameSetting(Settings::Setting<Settings::GPUAccuracy>* setting,
+ const QComboBox* combobox);
+
+void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting);
+void SetPerGameSetting(QComboBox* combobox, const Settings::Setting<int>* setting);
+void SetPerGameSetting(QComboBox* combobox,
+ const Settings::Setting<Settings::RendererBackend>* setting);
+void SetPerGameSetting(QComboBox* combobox,
+ const Settings::Setting<Settings::GPUAccuracy>* setting);
+
+void InsertGlobalItem(QComboBox* combobox);
+
+} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index f370c690f..cc021beec 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -11,6 +11,7 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_audio.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_audio.h"
ConfigureAudio::ConfigureAudio(QWidget* parent)
@@ -24,6 +25,11 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
&ConfigureAudio::UpdateAudioDevices);
+ ui->volume_label->setVisible(Settings::configuring_global);
+ ui->volume_combo_box->setVisible(!Settings::configuring_global);
+
+ SetupPerGameUI();
+
SetConfiguration();
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
@@ -41,8 +47,22 @@ void ConfigureAudio::SetConfiguration() {
SetAudioDeviceFromDeviceID();
- ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching);
- ui->volume_slider->setValue(Settings::values.volume * ui->volume_slider->maximum());
+ ui->volume_slider->setValue(Settings::values.volume.GetValue() * ui->volume_slider->maximum());
+
+ if (Settings::configuring_global) {
+ ui->toggle_audio_stretching->setChecked(
+ Settings::values.enable_audio_stretching.GetValue());
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->toggle_audio_stretching,
+ &Settings::values.enable_audio_stretching);
+ if (Settings::values.volume.UsingGlobal()) {
+ ui->volume_combo_box->setCurrentIndex(0);
+ ui->volume_slider->setEnabled(false);
+ } else {
+ ui->volume_combo_box->setCurrentIndex(1);
+ ui->volume_slider->setEnabled(true);
+ }
+ }
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
@@ -80,15 +100,36 @@ void ConfigureAudio::SetVolumeIndicatorText(int percentage) {
}
void ConfigureAudio::ApplyConfiguration() {
- Settings::values.sink_id =
- ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
- .toStdString();
- Settings::values.enable_audio_stretching = ui->toggle_audio_stretching->isChecked();
- Settings::values.audio_device_id =
- ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
- .toStdString();
- Settings::values.volume =
- static_cast<float>(ui->volume_slider->sliderPosition()) / ui->volume_slider->maximum();
+ if (Settings::configuring_global) {
+ Settings::values.sink_id =
+ ui->output_sink_combo_box->itemText(ui->output_sink_combo_box->currentIndex())
+ .toStdString();
+ Settings::values.audio_device_id =
+ ui->audio_device_combo_box->itemText(ui->audio_device_combo_box->currentIndex())
+ .toStdString();
+
+ // Guard if during game and set to game-specific value
+ if (Settings::values.enable_audio_stretching.UsingGlobal()) {
+ Settings::values.enable_audio_stretching.SetValue(
+ ui->toggle_audio_stretching->isChecked());
+ }
+ if (Settings::values.volume.UsingGlobal()) {
+ Settings::values.volume.SetValue(
+ static_cast<float>(ui->volume_slider->sliderPosition()) /
+ ui->volume_slider->maximum());
+ }
+ } else {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
+ ui->toggle_audio_stretching);
+ if (ui->volume_combo_box->currentIndex() == 0) {
+ Settings::values.volume.SetGlobal(true);
+ } else {
+ Settings::values.volume.SetGlobal(false);
+ Settings::values.volume.SetValue(
+ static_cast<float>(ui->volume_slider->sliderPosition()) /
+ ui->volume_slider->maximum());
+ }
+ }
}
void ConfigureAudio::changeEvent(QEvent* event) {
@@ -122,3 +163,22 @@ void ConfigureAudio::RetranslateUI() {
ui->retranslateUi(this);
SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
}
+
+void ConfigureAudio::SetupPerGameUI() {
+ if (Settings::configuring_global) {
+ ui->volume_slider->setEnabled(Settings::values.volume.UsingGlobal());
+ ui->toggle_audio_stretching->setEnabled(
+ Settings::values.enable_audio_stretching.UsingGlobal());
+
+ return;
+ }
+
+ ui->toggle_audio_stretching->setTristate(true);
+ connect(ui->volume_combo_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
+ this, [this](int index) { ui->volume_slider->setEnabled(index == 1); });
+
+ ui->output_sink_combo_box->setVisible(false);
+ ui->output_sink_label->setVisible(false);
+ ui->audio_device_combo_box->setVisible(false);
+ ui->audio_device_label->setVisible(false);
+}
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index ea83bd72d..d84f4a682 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -34,5 +34,7 @@ private:
void SetAudioDeviceFromDeviceID();
void SetVolumeIndicatorText(int percentage);
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureAudio> ui;
};
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index a098b9acc..862ccb988 100644
--- a/src/yuzu/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>188</width>
- <height>246</height>
+ <width>367</width>
+ <height>368</height>
</rect>
</property>
<layout class="QVBoxLayout">
@@ -18,9 +18,9 @@
</property>
<layout class="QVBoxLayout">
<item>
- <layout class="QHBoxLayout">
+ <layout class="QHBoxLayout" name="_3">
<item>
- <widget class="QLabel" name="label_1">
+ <widget class="QLabel" name="output_sink_label">
<property name="text">
<string>Output Engine:</string>
</property>
@@ -31,20 +31,20 @@
</item>
</layout>
</item>
- <item>
- <widget class="QCheckBox" name="toggle_audio_stretching">
- <property name="toolTip">
- <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string>
- </property>
- <property name="text">
- <string>Enable audio stretching</string>
- </property>
- </widget>
- </item>
<item>
- <layout class="QHBoxLayout">
+ <widget class="QCheckBox" name="toggle_audio_stretching">
+ <property name="toolTip">
+ <string>This post-processing effect adjusts audio speed to match emulation speed and helps prevent audio stutter. This however increases audio latency.</string>
+ </property>
+ <property name="text">
+ <string>Enable audio stretching</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="_2">
<item>
- <widget class="QLabel" name="label_2">
+ <widget class="QLabel" name="audio_device_label">
<property name="text">
<string>Audio Device:</string>
</property>
@@ -61,7 +61,21 @@
<number>0</number>
</property>
<item>
- <widget class="QLabel" name="label_3">
+ <widget class="QComboBox" name="volume_combo_box">
+ <item>
+ <property name="text">
+ <string>Use global volume</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Set volume:</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="volume_label">
<property name="text">
<string>Volume:</string>
</property>
@@ -74,7 +88,7 @@
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>40</width>
+ <width>30</width>
<height>20</height>
</size>
</property>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index df4473b46..5918e9972 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -14,6 +14,8 @@
ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
: QDialog(parent), ui(new Ui::ConfigureDialog), registry(registry) {
+ Settings::configuring_global = true;
+
ui->setupUi(this);
ui->hotkeysTab->Populate(registry);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 74b2ad537..1fb62d1cf 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -7,17 +7,21 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_general.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_general.h"
#include "yuzu/uisettings.h"
ConfigureGeneral::ConfigureGeneral(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGeneral) {
-
ui->setupUi(this);
+ SetupPerGameUI();
+
SetConfiguration();
- connect(ui->toggle_frame_limit, &QCheckBox::toggled, ui->frame_limit, &QSpinBox::setEnabled);
+ connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, [this]() {
+ ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked);
+ });
}
ConfigureGeneral::~ConfigureGeneral() = default;
@@ -26,27 +30,56 @@ void ConfigureGeneral::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
ui->use_multi_core->setEnabled(runtime_lock);
- ui->use_multi_core->setChecked(Settings::values.use_multi_core);
+ ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot);
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background);
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse);
- ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
- ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked());
- ui->frame_limit->setValue(Settings::values.frame_limit);
+ ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
+ ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
+
+ if (!Settings::configuring_global) {
+ if (Settings::values.use_multi_core.UsingGlobal()) {
+ ui->use_multi_core->setCheckState(Qt::PartiallyChecked);
+ }
+ if (Settings::values.use_frame_limit.UsingGlobal()) {
+ ui->toggle_frame_limit->setCheckState(Qt::PartiallyChecked);
+ }
+ }
+
+ ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked &&
+ ui->toggle_frame_limit->isEnabled());
}
void ConfigureGeneral::ApplyConfiguration() {
- UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
- UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
- UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
- UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
-
- Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked();
- Settings::values.frame_limit = ui->frame_limit->value();
- Settings::values.use_multi_core = ui->use_multi_core->isChecked();
+ if (Settings::configuring_global) {
+ UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
+ UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
+ UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
+ UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
+
+ // Guard if during game and set to game-specific value
+ if (Settings::values.use_frame_limit.UsingGlobal()) {
+ Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
+ Qt::Checked);
+ Settings::values.frame_limit.SetValue(ui->frame_limit->value());
+ Settings::values.use_multi_core.SetValue(ui->use_multi_core->isChecked());
+ }
+ } else {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core,
+ ui->use_multi_core);
+
+ bool global_frame_limit = ui->toggle_frame_limit->checkState() == Qt::PartiallyChecked;
+ Settings::values.use_frame_limit.SetGlobal(global_frame_limit);
+ Settings::values.frame_limit.SetGlobal(global_frame_limit);
+ if (!global_frame_limit) {
+ Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
+ Qt::Checked);
+ Settings::values.frame_limit.SetValue(ui->frame_limit->value());
+ }
+ }
}
void ConfigureGeneral::changeEvent(QEvent* event) {
@@ -60,3 +93,20 @@ void ConfigureGeneral::changeEvent(QEvent* event) {
void ConfigureGeneral::RetranslateUI() {
ui->retranslateUi(this);
}
+
+void ConfigureGeneral::SetupPerGameUI() {
+ if (Settings::configuring_global) {
+ ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal());
+ ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
+
+ return;
+ }
+
+ ui->toggle_check_exit->setVisible(false);
+ ui->toggle_user_on_boot->setVisible(false);
+ ui->toggle_background_pause->setVisible(false);
+ ui->toggle_hide_mouse->setVisible(false);
+
+ ui->toggle_frame_limit->setTristate(true);
+ ui->use_multi_core->setTristate(true);
+}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index ef05ce065..9c785c22e 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -28,5 +28,7 @@ private:
void SetConfiguration();
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureGeneral> ui;
};
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 304625cd7..cb4706bd6 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -13,6 +13,7 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_graphics.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_graphics.h"
#ifdef HAS_VULKAN
@@ -21,16 +22,18 @@
ConfigureGraphics::ConfigureGraphics(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGraphics) {
- vulkan_device = Settings::values.vulkan_device;
+ vulkan_device = Settings::values.vulkan_device.GetValue();
RetrieveVulkanDevices();
ui->setupUi(this);
+ SetupPerGameUI();
+
SetConfiguration();
- connect(ui->api, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
+ connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this] { UpdateDeviceComboBox(); });
- connect(ui->device, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this,
+ connect(ui->device, qOverload<int>(&QComboBox::activated), this,
[this](int device) { UpdateDeviceSelection(device); });
connect(ui->bg_button, &QPushButton::clicked, this, [this] {
@@ -40,6 +43,9 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
}
UpdateBackgroundColorButton(new_bg_color);
});
+
+ ui->bg_label->setVisible(Settings::configuring_global);
+ ui->bg_combobox->setVisible(!Settings::configuring_global);
}
void ConfigureGraphics::UpdateDeviceSelection(int device) {
@@ -57,27 +63,95 @@ void ConfigureGraphics::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
ui->api->setEnabled(runtime_lock);
- ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend));
- ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio);
- ui->use_disk_shader_cache->setEnabled(runtime_lock);
- ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache);
ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
- ui->use_asynchronous_gpu_emulation->setChecked(Settings::values.use_asynchronous_gpu_emulation);
- UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
- Settings::values.bg_blue));
+ ui->use_disk_shader_cache->setEnabled(runtime_lock);
+
+ if (Settings::configuring_global) {
+ ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
+ ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
+ ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
+ ui->use_asynchronous_gpu_emulation->setChecked(
+ Settings::values.use_asynchronous_gpu_emulation.GetValue());
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->use_disk_shader_cache,
+ &Settings::values.use_disk_shader_cache);
+ ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_gpu_emulation,
+ &Settings::values.use_asynchronous_gpu_emulation);
+
+ ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
+ ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
+ &Settings::values.aspect_ratio);
+
+ ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
+ ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
+ }
+
+ UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red.GetValue(),
+ Settings::values.bg_green.GetValue(),
+ Settings::values.bg_blue.GetValue()));
UpdateDeviceComboBox();
}
void ConfigureGraphics::ApplyConfiguration() {
- Settings::values.renderer_backend = GetCurrentGraphicsBackend();
- Settings::values.vulkan_device = vulkan_device;
- Settings::values.aspect_ratio = ui->aspect_ratio_combobox->currentIndex();
- Settings::values.use_disk_shader_cache = ui->use_disk_shader_cache->isChecked();
- Settings::values.use_asynchronous_gpu_emulation =
- ui->use_asynchronous_gpu_emulation->isChecked();
- Settings::values.bg_red = static_cast<float>(bg_color.redF());
- Settings::values.bg_green = static_cast<float>(bg_color.greenF());
- Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
+ if (Settings::configuring_global) {
+ // Guard if during game and set to game-specific value
+ if (Settings::values.renderer_backend.UsingGlobal()) {
+ Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
+ }
+ if (Settings::values.vulkan_device.UsingGlobal()) {
+ Settings::values.vulkan_device.SetValue(vulkan_device);
+ }
+ if (Settings::values.aspect_ratio.UsingGlobal()) {
+ Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
+ }
+ if (Settings::values.use_disk_shader_cache.UsingGlobal()) {
+ Settings::values.use_disk_shader_cache.SetValue(ui->use_disk_shader_cache->isChecked());
+ }
+ if (Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()) {
+ Settings::values.use_asynchronous_gpu_emulation.SetValue(
+ ui->use_asynchronous_gpu_emulation->isChecked());
+ }
+ if (Settings::values.bg_red.UsingGlobal()) {
+ Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
+ Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
+ Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF()));
+ }
+ } else {
+ if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.renderer_backend.SetGlobal(true);
+ Settings::values.vulkan_device.SetGlobal(true);
+ } else {
+ Settings::values.renderer_backend.SetGlobal(false);
+ Settings::values.renderer_backend.SetValue(GetCurrentGraphicsBackend());
+ if (GetCurrentGraphicsBackend() == Settings::RendererBackend::Vulkan) {
+ Settings::values.vulkan_device.SetGlobal(false);
+ Settings::values.vulkan_device.SetValue(vulkan_device);
+ } else {
+ Settings::values.vulkan_device.SetGlobal(true);
+ }
+ }
+
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
+ ui->aspect_ratio_combobox);
+
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
+ ui->use_disk_shader_cache);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
+ ui->use_asynchronous_gpu_emulation);
+
+ if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.bg_red.SetGlobal(true);
+ Settings::values.bg_green.SetGlobal(true);
+ Settings::values.bg_blue.SetGlobal(true);
+ } else {
+ Settings::values.bg_red.SetGlobal(false);
+ Settings::values.bg_green.SetGlobal(false);
+ Settings::values.bg_blue.SetGlobal(false);
+ Settings::values.bg_red.SetValue(static_cast<float>(bg_color.redF()));
+ Settings::values.bg_green.SetValue(static_cast<float>(bg_color.greenF()));
+ Settings::values.bg_blue.SetValue(static_cast<float>(bg_color.blueF()));
+ }
+ }
}
void ConfigureGraphics::changeEvent(QEvent* event) {
@@ -106,19 +180,27 @@ void ConfigureGraphics::UpdateDeviceComboBox() {
ui->device->clear();
bool enabled = false;
+
+ if (!Settings::configuring_global &&
+ ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ vulkan_device = Settings::values.vulkan_device.GetValue();
+ }
switch (GetCurrentGraphicsBackend()) {
case Settings::RendererBackend::OpenGL:
ui->device->addItem(tr("OpenGL Graphics Device"));
enabled = false;
break;
case Settings::RendererBackend::Vulkan:
- for (const auto device : vulkan_devices) {
+ for (const auto& device : vulkan_devices) {
ui->device->addItem(device);
}
ui->device->setCurrentIndex(vulkan_device);
enabled = !vulkan_devices.empty();
break;
}
+ // If in per-game config and use global is selected, don't enable.
+ enabled &= !(!Settings::configuring_global &&
+ ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX);
ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn());
}
@@ -132,5 +214,37 @@ void ConfigureGraphics::RetrieveVulkanDevices() {
}
Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
- return static_cast<Settings::RendererBackend>(ui->api->currentIndex());
+ if (Settings::configuring_global) {
+ return static_cast<Settings::RendererBackend>(ui->api->currentIndex());
+ }
+
+ if (ui->api->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.renderer_backend.SetGlobal(true);
+ return Settings::values.renderer_backend.GetValue();
+ }
+ Settings::values.renderer_backend.SetGlobal(false);
+ return static_cast<Settings::RendererBackend>(ui->api->currentIndex() -
+ ConfigurationShared::USE_GLOBAL_OFFSET);
+}
+
+void ConfigureGraphics::SetupPerGameUI() {
+ if (Settings::configuring_global) {
+ ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
+ ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
+ ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
+ ui->use_asynchronous_gpu_emulation->setEnabled(
+ Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
+ ui->use_disk_shader_cache->setEnabled(Settings::values.use_disk_shader_cache.UsingGlobal());
+ ui->bg_button->setEnabled(Settings::values.bg_red.UsingGlobal());
+
+ return;
+ }
+
+ connect(ui->bg_combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this,
+ [this](int index) { ui->bg_button->setEnabled(index == 1); });
+
+ ui->use_disk_shader_cache->setTristate(true);
+ ui->use_asynchronous_gpu_emulation->setTristate(true);
+ ConfigurationShared::InsertGlobalItem(ui->aspect_ratio_combobox);
+ ConfigurationShared::InsertGlobalItem(ui->api);
}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 7e0596d9c..24f01c739 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -35,6 +35,8 @@ private:
void RetrieveVulkanDevices();
+ void SetupPerGameUI();
+
Settings::RendererBackend GetCurrentGraphicsBackend() const;
std::unique_ptr<Ui::ConfigureGraphics> ui;
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 6e75447a5..62418fc14 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -122,6 +122,29 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
+ <widget class="QComboBox" name="bg_combobox">
+ <property name="currentText">
+ <string>Use global background color</string>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="maxVisibleItems">
+ <number>10</number>
+ </property>
+ <item>
+ <property name="text">
+ <string>Use global background color</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Set background color:</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="bg_label">
<property name="text">
<string>Background Color:</string>
@@ -129,6 +152,19 @@
</widget>
</item>
<item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
<widget class="QPushButton" name="bg_button">
<property name="maximumSize">
<size>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index be5006ad3..7c0fa7ec5 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -5,6 +5,7 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_graphics_advanced.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_graphics_advanced.h"
ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent)
@@ -12,6 +13,8 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(QWidget* parent)
ui->setupUi(this);
+ SetupPerGameUI();
+
SetConfiguration();
}
@@ -19,26 +22,81 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
void ConfigureGraphicsAdvanced::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
- ui->gpu_accuracy->setCurrentIndex(static_cast<int>(Settings::values.gpu_accuracy));
ui->use_vsync->setEnabled(runtime_lock);
- ui->use_vsync->setChecked(Settings::values.use_vsync);
ui->use_assembly_shaders->setEnabled(runtime_lock);
- ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders);
- ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time);
ui->force_30fps_mode->setEnabled(runtime_lock);
- ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode);
ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
- ui->anisotropic_filtering_combobox->setCurrentIndex(Settings::values.max_anisotropy);
+
+ if (Settings::configuring_global) {
+ ui->gpu_accuracy->setCurrentIndex(
+ static_cast<int>(Settings::values.gpu_accuracy.GetValue()));
+ ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
+ ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue());
+ ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
+ ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode.GetValue());
+ ui->anisotropic_filtering_combobox->setCurrentIndex(
+ Settings::values.max_anisotropy.GetValue());
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->gpu_accuracy, &Settings::values.gpu_accuracy);
+ ConfigurationShared::SetPerGameSetting(ui->use_vsync, &Settings::values.use_vsync);
+ ConfigurationShared::SetPerGameSetting(ui->use_assembly_shaders,
+ &Settings::values.use_assembly_shaders);
+ ConfigurationShared::SetPerGameSetting(ui->use_fast_gpu_time,
+ &Settings::values.use_fast_gpu_time);
+ ConfigurationShared::SetPerGameSetting(ui->force_30fps_mode,
+ &Settings::values.force_30fps_mode);
+ ConfigurationShared::SetPerGameSetting(ui->anisotropic_filtering_combobox,
+ &Settings::values.max_anisotropy);
+ }
}
void ConfigureGraphicsAdvanced::ApplyConfiguration() {
- auto gpu_accuracy = static_cast<Settings::GPUAccuracy>(ui->gpu_accuracy->currentIndex());
- Settings::values.gpu_accuracy = gpu_accuracy;
- Settings::values.use_vsync = ui->use_vsync->isChecked();
- Settings::values.use_assembly_shaders = ui->use_assembly_shaders->isChecked();
- Settings::values.use_fast_gpu_time = ui->use_fast_gpu_time->isChecked();
- Settings::values.force_30fps_mode = ui->force_30fps_mode->isChecked();
- Settings::values.max_anisotropy = ui->anisotropic_filtering_combobox->currentIndex();
+ // Subtract 2 if configuring per-game (separator and "use global configuration" take 2 slots)
+ const auto gpu_accuracy = static_cast<Settings::GPUAccuracy>(
+ ui->gpu_accuracy->currentIndex() -
+ ((Settings::configuring_global) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
+
+ if (Settings::configuring_global) {
+ // Must guard in case of a during-game configuration when set to be game-specific.
+ if (Settings::values.gpu_accuracy.UsingGlobal()) {
+ Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
+ }
+ if (Settings::values.use_vsync.UsingGlobal()) {
+ Settings::values.use_vsync.SetValue(ui->use_vsync->isChecked());
+ }
+ if (Settings::values.use_assembly_shaders.UsingGlobal()) {
+ Settings::values.use_assembly_shaders.SetValue(ui->use_assembly_shaders->isChecked());
+ }
+ if (Settings::values.use_fast_gpu_time.UsingGlobal()) {
+ Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked());
+ }
+ if (Settings::values.force_30fps_mode.UsingGlobal()) {
+ Settings::values.force_30fps_mode.SetValue(ui->force_30fps_mode->isChecked());
+ }
+ if (Settings::values.max_anisotropy.UsingGlobal()) {
+ Settings::values.max_anisotropy.SetValue(
+ ui->anisotropic_filtering_combobox->currentIndex());
+ }
+ } else {
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
+ ui->anisotropic_filtering_combobox);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
+ ui->use_assembly_shaders);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
+ ui->use_fast_gpu_time);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.force_30fps_mode,
+ ui->force_30fps_mode);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
+ ui->anisotropic_filtering_combobox);
+
+ if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
+ Settings::values.gpu_accuracy.SetGlobal(true);
+ } else {
+ Settings::values.gpu_accuracy.SetGlobal(false);
+ Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
+ }
+ }
}
void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
@@ -52,3 +110,25 @@ void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
void ConfigureGraphicsAdvanced::RetranslateUI() {
ui->retranslateUi(this);
}
+
+void ConfigureGraphicsAdvanced::SetupPerGameUI() {
+ // Disable if not global (only happens during game)
+ if (Settings::configuring_global) {
+ ui->gpu_accuracy->setEnabled(Settings::values.gpu_accuracy.UsingGlobal());
+ ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal());
+ ui->use_assembly_shaders->setEnabled(Settings::values.use_assembly_shaders.UsingGlobal());
+ ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
+ ui->force_30fps_mode->setEnabled(Settings::values.force_30fps_mode.UsingGlobal());
+ ui->anisotropic_filtering_combobox->setEnabled(
+ Settings::values.max_anisotropy.UsingGlobal());
+
+ return;
+ }
+
+ ConfigurationShared::InsertGlobalItem(ui->gpu_accuracy);
+ ui->use_vsync->setTristate(true);
+ ui->use_assembly_shaders->setTristate(true);
+ ui->use_fast_gpu_time->setTristate(true);
+ ui->force_30fps_mode->setTristate(true);
+ ConfigurationShared::InsertGlobalItem(ui->anisotropic_filtering_combobox);
+}
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index bbc9d4355..c043588ff 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -26,5 +26,7 @@ private:
void SetConfiguration();
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
};
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
new file mode 100644
index 000000000..1e49f0787
--- /dev/null
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -0,0 +1,140 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include <QCheckBox>
+#include <QHeaderView>
+#include <QMenu>
+#include <QStandardItemModel>
+#include <QString>
+#include <QTimer>
+#include <QTreeView>
+
+#include "common/common_paths.h"
+#include "common/file_util.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/xts_archive.h"
+#include "core/loader/loader.h"
+#include "ui_configure_per_game.h"
+#include "yuzu/configuration/config.h"
+#include "yuzu/configuration/configure_input.h"
+#include "yuzu/configuration/configure_per_game.h"
+#include "yuzu/uisettings.h"
+#include "yuzu/util/util.h"
+
+ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id)
+ : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) {
+ game_config = std::make_unique<Config>(fmt::format("{:016X}.ini", title_id), false);
+
+ Settings::configuring_global = false;
+
+ ui->setupUi(this);
+ setFocusPolicy(Qt::ClickFocus);
+ setWindowTitle(tr("Properties"));
+
+ ui->addonsTab->SetTitleId(title_id);
+
+ scene = new QGraphicsScene;
+ ui->icon_view->setScene(scene);
+
+ LoadConfiguration();
+}
+
+ConfigurePerGame::~ConfigurePerGame() = default;
+
+void ConfigurePerGame::ApplyConfiguration() {
+ ui->addonsTab->ApplyConfiguration();
+ ui->generalTab->ApplyConfiguration();
+ ui->systemTab->ApplyConfiguration();
+ ui->graphicsTab->ApplyConfiguration();
+ ui->graphicsAdvancedTab->ApplyConfiguration();
+ ui->audioTab->ApplyConfiguration();
+
+ Settings::Apply();
+ Settings::LogSettings();
+
+ game_config->Save();
+}
+
+void ConfigurePerGame::changeEvent(QEvent* event) {
+ if (event->type() == QEvent::LanguageChange) {
+ RetranslateUI();
+ }
+
+ QDialog::changeEvent(event);
+}
+
+void ConfigurePerGame::RetranslateUI() {
+ ui->retranslateUi(this);
+}
+
+void ConfigurePerGame::LoadFromFile(FileSys::VirtualFile file) {
+ this->file = std::move(file);
+ LoadConfiguration();
+}
+
+void ConfigurePerGame::LoadConfiguration() {
+ if (file == nullptr) {
+ return;
+ }
+
+ ui->addonsTab->LoadFromFile(file);
+
+ ui->display_title_id->setText(
+ QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper());
+
+ FileSys::PatchManager pm{title_id};
+ const auto control = pm.GetControlMetadata();
+ const auto loader = Loader::GetLoader(file);
+
+ if (control.first != nullptr) {
+ ui->display_version->setText(QString::fromStdString(control.first->GetVersionString()));
+ ui->display_name->setText(QString::fromStdString(control.first->GetApplicationName()));
+ ui->display_developer->setText(QString::fromStdString(control.first->GetDeveloperName()));
+ } else {
+ std::string title;
+ if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
+ ui->display_name->setText(QString::fromStdString(title));
+
+ FileSys::NACP nacp;
+ if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success)
+ ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName()));
+
+ ui->display_version->setText(QStringLiteral("1.0.0"));
+ }
+
+ if (control.second != nullptr) {
+ scene->clear();
+
+ QPixmap map;
+ const auto bytes = control.second->ReadAllBytes();
+ map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
+
+ scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
+ Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+ } else {
+ std::vector<u8> bytes;
+ if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) {
+ scene->clear();
+
+ QPixmap map;
+ map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
+
+ scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
+ Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+ }
+ }
+
+ ui->display_filename->setText(QString::fromStdString(file->GetName()));
+
+ ui->display_format->setText(
+ QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())));
+
+ const auto valueText = ReadableByteSize(file->GetSize());
+ ui->display_size->setText(valueText);
+}
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h
new file mode 100644
index 000000000..5f9a08cef
--- /dev/null
+++ b/src/yuzu/configuration/configure_per_game.h
@@ -0,0 +1,51 @@
+// Copyright 2020 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <QDialog>
+#include <QList>
+
+#include "core/file_sys/vfs_types.h"
+#include "yuzu/configuration/config.h"
+
+class QGraphicsScene;
+class QStandardItem;
+class QStandardItemModel;
+class QTreeView;
+class QVBoxLayout;
+
+namespace Ui {
+class ConfigurePerGame;
+}
+
+class ConfigurePerGame : public QDialog {
+ Q_OBJECT
+
+public:
+ explicit ConfigurePerGame(QWidget* parent, u64 title_id);
+ ~ConfigurePerGame() override;
+
+ /// Save all button configurations to settings file
+ void ApplyConfiguration();
+
+ void LoadFromFile(FileSys::VirtualFile file);
+
+private:
+ void changeEvent(QEvent* event) override;
+ void RetranslateUI();
+
+ void LoadConfiguration();
+
+ std::unique_ptr<Ui::ConfigurePerGame> ui;
+ FileSys::VirtualFile file;
+ u64 title_id;
+
+ QGraphicsScene* scene;
+
+ std::unique_ptr<Config> game_config;
+};
diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui
new file mode 100644
index 000000000..d2057c4ab
--- /dev/null
+++ b/src/yuzu/configuration/configure_per_game.ui
@@ -0,0 +1,350 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigurePerGame</class>
+ <widget class="QDialog" name="ConfigurePerGame">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Info</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGraphicsView" name="icon_view">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>256</width>
+ <height>256</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>256</width>
+ <height>256</height>
+ </size>
+ </property>
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="interactive">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="6" column="1">
+ <widget class="QLineEdit" name="display_size">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="display_version">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Name</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Title ID</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="display_title_id">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QLineEdit" name="display_filename">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="display_format">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Filename</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="display_name">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="display_developer">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Format</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Version</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Size</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Developer</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="VerticalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2"/>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="usesScrollButtons">
+ <bool>true</bool>
+ </property>
+ <property name="documentMode">
+ <bool>false</bool>
+ </property>
+ <property name="tabsClosable">
+ <bool>false</bool>
+ </property>
+ <widget class="ConfigurePerGameAddons" name="addonsTab">
+ <attribute name="title">
+ <string>Add-Ons</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureGeneral" name="generalTab">
+ <attribute name="title">
+ <string>General</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureSystem" name="systemTab">
+ <attribute name="title">
+ <string>System</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureGraphics" name="graphicsTab">
+ <attribute name="title">
+ <string>Graphics</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab">
+ <attribute name="title">
+ <string>Adv. Graphics</string>
+ </attribute>
+ </widget>
+ <widget class="ConfigureAudio" name="audioTab">
+ <attribute name="title">
+ <string>Audio</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ConfigureGeneral</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_general.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureSystem</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_system.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureAudio</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_audio.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureGraphics</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_graphics.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigureGraphicsAdvanced</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_graphics_advanced.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>ConfigurePerGameAddons</class>
+ <extends>QWidget</extends>
+ <header>configuration/configure_per_game_addons.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ConfigurePerGame</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ConfigurePerGame</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/yuzu/configuration/configure_per_general.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp
index d7f259f12..478d5d3a1 100644
--- a/src/yuzu/configuration/configure_per_general.cpp
+++ b/src/yuzu/configuration/configure_per_game_addons.cpp
@@ -15,23 +15,20 @@
#include "common/common_paths.h"
#include "common/file_util.h"
-#include "core/file_sys/control_metadata.h"
+#include "core/core.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/xts_archive.h"
#include "core/loader/loader.h"
-#include "ui_configure_per_general.h"
+#include "ui_configure_per_game_addons.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_input.h"
-#include "yuzu/configuration/configure_per_general.h"
+#include "yuzu/configuration/configure_per_game_addons.h"
#include "yuzu/uisettings.h"
#include "yuzu/util/util.h"
-ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
- : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGameGeneral>()), title_id(title_id) {
-
+ConfigurePerGameAddons::ConfigurePerGameAddons(QWidget* parent)
+ : QWidget(parent), ui(new Ui::ConfigurePerGameAddons) {
ui->setupUi(this);
- setFocusPolicy(Qt::ClickFocus);
- setWindowTitle(tr("Properties"));
layout = new QVBoxLayout;
tree_view = new QTreeView;
@@ -52,7 +49,7 @@ ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
item_model->setHeaderData(1, Qt::Horizontal, tr("Version"));
// We must register all custom types with the Qt Automoc system so that we are able to use it
- // with signals/slots. In this case, QList falls under the umbrells of custom types.
+ // with signals/slots. In this case, QList falls under the umbrella of custom types.
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
layout->setContentsMargins(0, 0, 0, 0);
@@ -61,18 +58,15 @@ ConfigurePerGameGeneral::ConfigurePerGameGeneral(QWidget* parent, u64 title_id)
ui->scrollArea->setLayout(layout);
- scene = new QGraphicsScene;
- ui->icon_view->setScene(scene);
+ ui->scrollArea->setEnabled(!Core::System::GetInstance().IsPoweredOn());
connect(item_model, &QStandardItemModel::itemChanged,
[] { UISettings::values.is_game_list_reload_pending.exchange(true); });
-
- LoadConfiguration();
}
-ConfigurePerGameGeneral::~ConfigurePerGameGeneral() = default;
+ConfigurePerGameAddons::~ConfigurePerGameAddons() = default;
-void ConfigurePerGameGeneral::ApplyConfiguration() {
+void ConfigurePerGameAddons::ApplyConfiguration() {
std::vector<std::string> disabled_addons;
for (const auto& item : list_items) {
@@ -92,72 +86,35 @@ void ConfigurePerGameGeneral::ApplyConfiguration() {
Settings::values.disabled_addons[title_id] = disabled_addons;
}
-void ConfigurePerGameGeneral::changeEvent(QEvent* event) {
+void ConfigurePerGameAddons::LoadFromFile(FileSys::VirtualFile file) {
+ this->file = std::move(file);
+ LoadConfiguration();
+}
+
+void ConfigurePerGameAddons::SetTitleId(u64 id) {
+ this->title_id = id;
+}
+
+void ConfigurePerGameAddons::changeEvent(QEvent* event) {
if (event->type() == QEvent::LanguageChange) {
RetranslateUI();
}
- QDialog::changeEvent(event);
+ QWidget::changeEvent(event);
}
-void ConfigurePerGameGeneral::RetranslateUI() {
+void ConfigurePerGameAddons::RetranslateUI() {
ui->retranslateUi(this);
}
-void ConfigurePerGameGeneral::LoadFromFile(FileSys::VirtualFile file) {
- this->file = std::move(file);
- LoadConfiguration();
-}
-
-void ConfigurePerGameGeneral::LoadConfiguration() {
+void ConfigurePerGameAddons::LoadConfiguration() {
if (file == nullptr) {
return;
}
- ui->display_title_id->setText(QString::fromStdString(fmt::format("{:016X}", title_id)));
-
FileSys::PatchManager pm{title_id};
- const auto control = pm.GetControlMetadata();
const auto loader = Loader::GetLoader(file);
- if (control.first != nullptr) {
- ui->display_version->setText(QString::fromStdString(control.first->GetVersionString()));
- ui->display_name->setText(QString::fromStdString(control.first->GetApplicationName()));
- ui->display_developer->setText(QString::fromStdString(control.first->GetDeveloperName()));
- } else {
- std::string title;
- if (loader->ReadTitle(title) == Loader::ResultStatus::Success)
- ui->display_name->setText(QString::fromStdString(title));
-
- FileSys::NACP nacp;
- if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success)
- ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName()));
-
- ui->display_version->setText(QStringLiteral("1.0.0"));
- }
-
- if (control.second != nullptr) {
- scene->clear();
-
- QPixmap map;
- const auto bytes = control.second->ReadAllBytes();
- map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
-
- scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
- Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
- } else {
- std::vector<u8> bytes;
- if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) {
- scene->clear();
-
- QPixmap map;
- map.loadFromData(bytes.data(), static_cast<u32>(bytes.size()));
-
- scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(),
- Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
- }
- }
-
FileSys::VirtualFile update_raw;
loader->ReadUpdateRaw(update_raw);
@@ -182,12 +139,4 @@ void ConfigurePerGameGeneral::LoadConfiguration() {
}
tree_view->setColumnWidth(0, 5 * tree_view->width() / 16);
-
- ui->display_filename->setText(QString::fromStdString(file->GetName()));
-
- ui->display_format->setText(
- QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())));
-
- const auto valueText = ReadableByteSize(file->GetSize());
- ui->display_size->setText(valueText);
}
diff --git a/src/yuzu/configuration/configure_per_general.h b/src/yuzu/configuration/configure_per_game_addons.h
index a3b2cdeff..a00ec3539 100644
--- a/src/yuzu/configuration/configure_per_general.h
+++ b/src/yuzu/configuration/configure_per_game_addons.h
@@ -1,4 +1,4 @@
-// Copyright 2016 Citra Emulator Project
+// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,7 +7,6 @@
#include <memory>
#include <vector>
-#include <QDialog>
#include <QList>
#include "core/file_sys/vfs_types.h"
@@ -19,35 +18,36 @@ class QTreeView;
class QVBoxLayout;
namespace Ui {
-class ConfigurePerGameGeneral;
+class ConfigurePerGameAddons;
}
-class ConfigurePerGameGeneral : public QDialog {
+class ConfigurePerGameAddons : public QWidget {
Q_OBJECT
public:
- explicit ConfigurePerGameGeneral(QWidget* parent, u64 title_id);
- ~ConfigurePerGameGeneral() override;
+ explicit ConfigurePerGameAddons(QWidget* parent = nullptr);
+ ~ConfigurePerGameAddons() override;
/// Save all button configurations to settings file
void ApplyConfiguration();
void LoadFromFile(FileSys::VirtualFile file);
+ void SetTitleId(u64 id);
+
private:
void changeEvent(QEvent* event) override;
void RetranslateUI();
void LoadConfiguration();
- std::unique_ptr<Ui::ConfigurePerGameGeneral> ui;
+ std::unique_ptr<Ui::ConfigurePerGameAddons> ui;
FileSys::VirtualFile file;
u64 title_id;
QVBoxLayout* layout;
QTreeView* tree_view;
QStandardItemModel* item_model;
- QGraphicsScene* scene;
std::vector<QList<QStandardItem*>> list_items;
};
diff --git a/src/yuzu/configuration/configure_per_game_addons.ui b/src/yuzu/configuration/configure_per_game_addons.ui
new file mode 100644
index 000000000..aefdebfcd
--- /dev/null
+++ b/src/yuzu/configuration/configure_per_game_addons.ui
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigurePerGameAddons</class>
+ <widget class="QWidget" name="ConfigurePerGameAddons">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>280</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/yuzu/configuration/configure_per_general.ui b/src/yuzu/configuration/configure_per_general.ui
deleted file mode 100644
index 8fdd96fa4..000000000
--- a/src/yuzu/configuration/configure_per_general.ui
+++ /dev/null
@@ -1,276 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ConfigurePerGameGeneral</class>
- <widget class="QDialog" name="ConfigurePerGameGeneral">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>400</width>
- <height>520</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>ConfigurePerGameGeneral</string>
- </property>
- <layout class="QHBoxLayout" name="HorizontalLayout">
- <item>
- <layout class="QVBoxLayout" name="VerticalLayout">
- <item>
- <widget class="QGroupBox" name="GeneralGroupBox">
- <property name="title">
- <string>Info</string>
- </property>
- <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
- <item>
- <layout class="QGridLayout" name="gridLayout_2">
- <item row="6" column="1" colspan="2">
- <widget class="QLineEdit" name="display_filename">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="display_name">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Developer</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1" colspan="2">
- <widget class="QLineEdit" name="display_size">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Name</string>
- </property>
- </widget>
- </item>
- <item row="6" column="0">
- <widget class="QLabel" name="label_7">
- <property name="text">
- <string>Filename</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QLabel" name="label_3">
- <property name="text">
- <string>Version</string>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>Format</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QLineEdit" name="display_version">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QLineEdit" name="display_format">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QLabel" name="label_6">
- <property name="text">
- <string>Size</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="display_developer">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QLabel" name="label_4">
- <property name="text">
- <string>Title ID</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QLineEdit" name="display_title_id">
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="readOnly">
- <bool>true</bool>
- </property>
- </widget>
- </item>
- <item row="0" column="2" rowspan="5">
- <widget class="QGraphicsView" name="icon_view">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>128</width>
- <height>128</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>128</width>
- <height>128</height>
- </size>
- </property>
- <property name="verticalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="sizeAdjustPolicy">
- <enum>QAbstractScrollArea::AdjustToContents</enum>
- </property>
- <property name="interactive">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="PerformanceGroupBox">
- <property name="title">
- <string>Add-Ons</string>
- </property>
- <layout class="QHBoxLayout" name="PerformanceHorizontalLayout">
- <item>
- <widget class="QScrollArea" name="scrollArea">
- <property name="widgetResizable">
- <bool>true</bool>
- </property>
- <widget class="QWidget" name="scrollAreaWidgetContents">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>350</width>
- <height>169</height>
- </rect>
- </property>
- </widget>
- </widget>
- </item>
- <item>
- <layout class="QVBoxLayout" name="PerformanceVerticalLayout"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeType">
- <enum>QSizePolicy::Fixed</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <resources/>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>ConfigurePerGameGeneral</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>269</x>
- <y>567</y>
- </hint>
- <hint type="destinationlabel">
- <x>269</x>
- <y>294</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>ConfigurePerGameGeneral</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>269</x>
- <y>567</y>
- </hint>
- <hint type="destinationlabel">
- <x>269</x>
- <y>294</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 10315e7a6..68e02738b 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -14,6 +14,7 @@
#include "core/core.h"
#include "core/settings.h"
#include "ui_configure_system.h"
+#include "yuzu/configuration/configuration_shared.h"
#include "yuzu/configuration/configure_system.h"
ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureSystem) {
@@ -21,20 +22,25 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
&ConfigureSystem::RefreshConsoleID);
- connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) {
- ui->rng_seed_edit->setEnabled(checked);
- if (!checked) {
+ connect(ui->rng_seed_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
+ ui->rng_seed_edit->setEnabled(state == Qt::Checked);
+ if (state != Qt::Checked) {
ui->rng_seed_edit->setText(QStringLiteral("00000000"));
}
});
- connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](bool checked) {
- ui->custom_rtc_edit->setEnabled(checked);
- if (!checked) {
+ connect(ui->custom_rtc_checkbox, &QCheckBox::stateChanged, this, [this](int state) {
+ ui->custom_rtc_edit->setEnabled(state == Qt::Checked);
+ if (state != Qt::Checked) {
ui->custom_rtc_edit->setDateTime(QDateTime::currentDateTime());
}
});
+ ui->label_console_id->setVisible(Settings::configuring_global);
+ ui->button_regenerate_console_id->setVisible(Settings::configuring_global);
+
+ SetupPerGameUI();
+
SetConfiguration();
}
@@ -54,26 +60,58 @@ void ConfigureSystem::RetranslateUI() {
void ConfigureSystem::SetConfiguration() {
enabled = !Core::System::GetInstance().IsPoweredOn();
+ const auto rng_seed =
+ QStringLiteral("%1")
+ .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'})
+ .toUpper();
+ const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or(
+ std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
- ui->combo_language->setCurrentIndex(Settings::values.language_index);
- ui->combo_region->setCurrentIndex(Settings::values.region_index);
- ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index);
- ui->combo_sound->setCurrentIndex(Settings::values.sound_index);
-
- ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value());
- ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value());
-
- const auto rng_seed = QStringLiteral("%1")
- .arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'})
- .toUpper();
- ui->rng_seed_edit->setText(rng_seed);
-
- ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
- ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value());
+ if (Settings::configuring_global) {
+ ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
+ ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue());
+ ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue());
+ ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue());
+
+ ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
+ ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
+ Settings::values.rng_seed.UsingGlobal());
+ ui->rng_seed_edit->setText(rng_seed);
+
+ ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value());
+ ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() &&
+ Settings::values.rng_seed.UsingGlobal());
+ ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
+ } else {
+ ConfigurationShared::SetPerGameSetting(ui->combo_language,
+ &Settings::values.language_index);
+ ConfigurationShared::SetPerGameSetting(ui->combo_region, &Settings::values.region_index);
+ ConfigurationShared::SetPerGameSetting(ui->combo_time_zone,
+ &Settings::values.time_zone_index);
+ ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index);
+
+ if (Settings::values.rng_seed.UsingGlobal()) {
+ ui->rng_seed_checkbox->setCheckState(Qt::PartiallyChecked);
+ } else {
+ ui->rng_seed_checkbox->setCheckState(
+ Settings::values.rng_seed.GetValue().has_value() ? Qt::Checked : Qt::Unchecked);
+ ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value());
+ if (Settings::values.rng_seed.GetValue().has_value()) {
+ ui->rng_seed_edit->setText(rng_seed);
+ }
+ }
- const auto rtc_time = Settings::values.custom_rtc.value_or(
- std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
- ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
+ if (Settings::values.custom_rtc.UsingGlobal()) {
+ ui->custom_rtc_checkbox->setCheckState(Qt::PartiallyChecked);
+ } else {
+ ui->custom_rtc_checkbox->setCheckState(
+ Settings::values.custom_rtc.GetValue().has_value() ? Qt::Checked : Qt::Unchecked);
+ ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value());
+ if (Settings::values.custom_rtc.GetValue().has_value()) {
+ ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
+ }
+ }
+ }
}
void ConfigureSystem::ReadSystemSettings() {}
@@ -83,22 +121,78 @@ void ConfigureSystem::ApplyConfiguration() {
return;
}
- Settings::values.language_index = ui->combo_language->currentIndex();
- Settings::values.region_index = ui->combo_region->currentIndex();
- Settings::values.time_zone_index = ui->combo_time_zone->currentIndex();
- Settings::values.sound_index = ui->combo_sound->currentIndex();
+ if (Settings::configuring_global) {
+ // Guard if during game and set to game-specific value
+ if (Settings::values.language_index.UsingGlobal()) {
+ Settings::values.language_index.SetValue(ui->combo_language->currentIndex());
+ }
+ if (Settings::values.region_index.UsingGlobal()) {
+ Settings::values.region_index.SetValue(ui->combo_region->currentIndex());
+ }
+ if (Settings::values.time_zone_index.UsingGlobal()) {
+ Settings::values.time_zone_index.SetValue(ui->combo_time_zone->currentIndex());
+ }
+ if (Settings::values.sound_index.UsingGlobal()) {
+ Settings::values.sound_index.SetValue(ui->combo_sound->currentIndex());
+ }
+
+ if (Settings::values.rng_seed.UsingGlobal()) {
+ if (ui->rng_seed_checkbox->isChecked()) {
+ Settings::values.rng_seed.SetValue(
+ ui->rng_seed_edit->text().toULongLong(nullptr, 16));
+ } else {
+ Settings::values.rng_seed.SetValue(std::nullopt);
+ }
+ }
- if (ui->rng_seed_checkbox->isChecked()) {
- Settings::values.rng_seed = ui->rng_seed_edit->text().toULongLong(nullptr, 16);
+ if (Settings::values.custom_rtc.UsingGlobal()) {
+ if (ui->custom_rtc_checkbox->isChecked()) {
+ Settings::values.custom_rtc.SetValue(
+ std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
+ } else {
+ Settings::values.custom_rtc.SetValue(std::nullopt);
+ }
+ }
} else {
- Settings::values.rng_seed = std::nullopt;
- }
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.language_index,
+ ui->combo_language);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.region_index, ui->combo_region);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.time_zone_index,
+ ui->combo_time_zone);
+ ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
+
+ switch (ui->rng_seed_checkbox->checkState()) {
+ case Qt::Checked:
+ Settings::values.rng_seed.SetGlobal(false);
+ Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toULongLong(nullptr, 16));
+ break;
+ case Qt::Unchecked:
+ Settings::values.rng_seed.SetGlobal(false);
+ Settings::values.rng_seed.SetValue(std::nullopt);
+ break;
+ case Qt::PartiallyChecked:
+ Settings::values.rng_seed.SetGlobal(false);
+ Settings::values.rng_seed.SetValue(std::nullopt);
+ Settings::values.rng_seed.SetGlobal(true);
+ break;
+ }
- if (ui->custom_rtc_checkbox->isChecked()) {
- Settings::values.custom_rtc =
- std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch());
- } else {
- Settings::values.custom_rtc = std::nullopt;
+ switch (ui->custom_rtc_checkbox->checkState()) {
+ case Qt::Checked:
+ Settings::values.custom_rtc.SetGlobal(false);
+ Settings::values.custom_rtc.SetValue(
+ std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
+ break;
+ case Qt::Unchecked:
+ Settings::values.custom_rtc.SetGlobal(false);
+ Settings::values.custom_rtc.SetValue(std::nullopt);
+ break;
+ case Qt::PartiallyChecked:
+ Settings::values.custom_rtc.SetGlobal(false);
+ Settings::values.custom_rtc.SetValue(std::nullopt);
+ Settings::values.custom_rtc.SetGlobal(true);
+ break;
+ }
}
Settings::Apply();
@@ -120,3 +214,25 @@ void ConfigureSystem::RefreshConsoleID() {
ui->label_console_id->setText(
tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
}
+
+void ConfigureSystem::SetupPerGameUI() {
+ if (Settings::configuring_global) {
+ ui->combo_language->setEnabled(Settings::values.language_index.UsingGlobal());
+ ui->combo_region->setEnabled(Settings::values.region_index.UsingGlobal());
+ ui->combo_time_zone->setEnabled(Settings::values.time_zone_index.UsingGlobal());
+ ui->combo_sound->setEnabled(Settings::values.sound_index.UsingGlobal());
+ ui->rng_seed_checkbox->setEnabled(Settings::values.rng_seed.UsingGlobal());
+ ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.UsingGlobal());
+ ui->custom_rtc_checkbox->setEnabled(Settings::values.custom_rtc.UsingGlobal());
+ ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.UsingGlobal());
+
+ return;
+ }
+
+ ConfigurationShared::InsertGlobalItem(ui->combo_language);
+ ConfigurationShared::InsertGlobalItem(ui->combo_region);
+ ConfigurationShared::InsertGlobalItem(ui->combo_time_zone);
+ ConfigurationShared::InsertGlobalItem(ui->combo_sound);
+ ui->rng_seed_checkbox->setTristate(true);
+ ui->custom_rtc_checkbox->setTristate(true);
+}
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index 26d42d5c5..f317ef8b5 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -32,6 +32,8 @@ private:
void RefreshConsoleID();
+ void SetupPerGameUI();
+
std::unique_ptr<Ui::ConfigureSystem> ui;
bool enabled = false;