summaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
authorlat9nq <22451773+lat9nq@users.noreply.github.com>2023-06-11 05:40:39 +0200
committerlat9nq <22451773+lat9nq@users.noreply.github.com>2023-07-21 16:56:54 +0200
commit04d4b6ab802a1238eaca6c0a16d1a739503b81d9 (patch)
tree2e4c850092b6d6f5f50e3a6a648a217e3c7a283c /src/common
parentsettings: Remove redundant false literals (diff)
downloadyuzu-04d4b6ab802a1238eaca6c0a16d1a739503b81d9.tar
yuzu-04d4b6ab802a1238eaca6c0a16d1a739503b81d9.tar.gz
yuzu-04d4b6ab802a1238eaca6c0a16d1a739503b81d9.tar.bz2
yuzu-04d4b6ab802a1238eaca6c0a16d1a739503b81d9.tar.lz
yuzu-04d4b6ab802a1238eaca6c0a16d1a739503b81d9.tar.xz
yuzu-04d4b6ab802a1238eaca6c0a16d1a739503b81d9.tar.zst
yuzu-04d4b6ab802a1238eaca6c0a16d1a739503b81d9.zip
Diffstat (limited to '')
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/settings.cpp52
-rw-r--r--src/common/settings.h513
-rw-r--r--src/common/settings_common.h78
-rw-r--r--src/common/settings_setting.h413
5 files changed, 587 insertions, 471 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 5902dd617..3c8368bb2 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -110,9 +110,11 @@ add_library(common STATIC
scratch_buffer.h
settings.cpp
settings.h
+ settings_common.h
settings_enums.h
settings_input.cpp
settings_input.h
+ settings_setting.h
socket_types.h
spin_lock.cpp
spin_lock.h
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 84e90f893..10cdea844 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -7,10 +7,17 @@
#include <exception>
#include <stdexcept>
#endif
+#include <compare>
+#include <cstddef>
+#include <filesystem>
+#include <forward_list>
#include <functional>
#include <string_view>
+#include <type_traits>
+#include <fmt/core.h>
#include "common/assert.h"
+#include "common/fs/fs_util.h"
#include "common/fs/path_util.h"
#include "common/logging/log.h"
#include "common/settings.h"
@@ -18,6 +25,43 @@
namespace Settings {
+#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
+#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
+
+SETTING(AudioEngine, false);
+SETTING(bool, false);
+SETTING(int, false);
+SETTING(std::string, false);
+SETTING(u16, false);
+SWITCHABLE(AnisotropyMode, true);
+SWITCHABLE(AntiAliasing, false);
+SWITCHABLE(AspectRatio, true);
+SWITCHABLE(AstcDecodeMode, true);
+SWITCHABLE(AstcRecompression, true);
+SWITCHABLE(AudioMode, true);
+SWITCHABLE(CpuAccuracy, true);
+SWITCHABLE(FullscreenMode, true);
+SWITCHABLE(GpuAccuracy, true);
+SWITCHABLE(Language, true);
+SWITCHABLE(NvdecEmulation, false);
+SWITCHABLE(Region, true);
+SWITCHABLE(RendererBackend, true);
+SWITCHABLE(ScalingFilter, false);
+SWITCHABLE(ShaderBackend, true);
+SWITCHABLE(TimeZone, true);
+SETTING(VSyncMode, true);
+SWITCHABLE(bool, false);
+SWITCHABLE(int, false);
+SWITCHABLE(int, true);
+SWITCHABLE(s64, false);
+SWITCHABLE(u16, true);
+SWITCHABLE(u32, false);
+SWITCHABLE(u8, false);
+SWITCHABLE(u8, true);
+
+#undef SETTING
+#undef SWITCHABLE
+
Values values;
static bool configuring_global = true;
@@ -238,6 +282,14 @@ void UpdateRescalingInfo() {
info.active = info.up_scale != 1 || info.down_shift != 0;
}
+std::string BasicSetting::ToStringGlobal() const {
+ return {};
+}
+
+bool BasicSetting::UsingGlobal() const {
+ return true;
+}
+
void RestoreGlobalState(bool is_powered_on) {
// If a game is running, DO NOT restore the global settings state
if (is_powered_on) {
diff --git a/src/common/settings.h b/src/common/settings.h
index ec0686120..e03233eaf 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -5,54 +5,21 @@
#include <algorithm>
#include <array>
-#include <forward_list>
-#include <functional>
#include <map>
-#include <optional>
+#include <memory>
#include <stdexcept>
#include <string>
-#include <typeindex>
-#include <typeinfo>
#include <utility>
#include <vector>
#include "common/common_types.h"
+#include "common/settings_common.h"
#include "common/settings_enums.h"
#include "common/settings_input.h"
+#include "common/settings_setting.h"
namespace Settings {
-enum class Category : u32 {
- Audio,
- Core,
- Cpu,
- CpuDebug,
- CpuUnsafe,
- Renderer,
- RendererAdvanced,
- RendererDebug,
- System,
- SystemAudio,
- DataStorage,
- Debugging,
- DebuggingGraphics,
- Miscellaneous,
- Network,
- WebService,
- AddOns,
- Controls,
- Ui,
- UiGeneral,
- UiLayout,
- UiGameList,
- Screenshots,
- Shortcuts,
- Multiplayer,
- Services,
- Paths,
- MaxEnum,
-};
-
const char* TranslateCategory(Settings::Category category);
struct ResolutionScalingInfo {
@@ -78,441 +45,45 @@ struct ResolutionScalingInfo {
}
};
-class BasicSetting {
-protected:
- explicit BasicSetting() = default;
-
-public:
- virtual ~BasicSetting() = default;
-
- virtual Category Category() const = 0;
- virtual constexpr bool Switchable() const = 0;
- virtual std::string ToString() const = 0;
- virtual std::string ToStringGlobal() const {
- return {};
- }
- virtual void LoadString(const std::string& load) = 0;
- virtual std::string Canonicalize() const = 0;
- virtual const std::string& GetLabel() const = 0;
- virtual std::string DefaultToString() const = 0;
- virtual bool Save() const = 0;
- virtual std::type_index TypeId() const = 0;
- virtual constexpr bool IsEnum() const = 0;
- virtual bool RuntimeModfiable() const = 0;
- virtual void SetGlobal(bool global) {}
- virtual constexpr u32 Id() const = 0;
- virtual std::string MinVal() const = 0;
- virtual std::string MaxVal() const = 0;
- virtual bool UsingGlobal() const {
- return true;
- }
-};
-
-class Linkage {
-public:
- explicit Linkage(u32 initial_count = 0);
- ~Linkage();
- std::map<Category, std::forward_list<BasicSetting*>> by_category{};
- std::vector<std::function<void()>> restore_functions{};
- u32 count;
-};
-
-/** The Setting class is a simple resource manager. It defines a label and default value
- * alongside the actual value of the setting for simpler and less-error prone use with frontend
- * configurations. Specifying a default value and label is required. A minimum and maximum range
- * can be specified for sanitization.
- */
-template <typename Type, bool ranged = false>
-class Setting : public BasicSetting {
-protected:
- Setting() = default;
-
- /**
- * Only sets the setting to the given initializer, leaving the other members to their default
- * initializers.
- *
- * @param global_val Initial value of the setting
- */
- explicit Setting(const Type& val) : value{val} {}
-
-public:
- /**
- * Sets a default value, label, and setting value.
- *
- * @param linkage Setting registry
- * @param default_val Initial value of the setting, and default value of the setting
- * @param name Label for the setting
- * @param category_ Category of the setting AKA INI group
- */
- explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
- enum Category category_, bool save_ = true, bool runtime_modifiable_ = false)
- requires(!ranged)
- : value{default_val}, default_value{default_val}, label{name}, category{category_},
- id{linkage.count}, save{save_}, runtime_modifiable{runtime_modifiable_} {
- linkage.by_category[category].push_front(this);
- linkage.count++;
- }
- virtual ~Setting() = default;
-
- /**
- * Sets a default value, minimum value, maximum value, and label.
- *
- * @param linkage Setting registry
- * @param default_val Initial value of the setting, and default value of the setting
- * @param min_val Sets the minimum allowed value of the setting
- * @param max_val Sets the maximum allowed value of the setting
- * @param name Label for the setting
- * @param category_ Category of the setting AKA INI group
- */
- explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
- const Type& max_val, const std::string& name, enum Category category_,
- bool save_ = true, bool runtime_modifiable_ = false)
- requires(ranged)
- : value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val},
- label{name}, category{category_}, id{linkage.count}, save{save_},
- runtime_modifiable{runtime_modifiable_} {
- linkage.by_category[category].push_front(this);
- linkage.count++;
- }
-
- /**
- * Returns a reference to the setting's value.
- *
- * @returns A reference to the setting
- */
- [[nodiscard]] virtual const Type& GetValue() const {
- return value;
- }
-
- /**
- * Sets the setting to the given value.
- *
- * @param val The desired value
- */
- virtual void SetValue(const Type& val) {
- Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
- std::swap(value, temp);
- }
-
- /**
- * Returns the value that this setting was created with.
- *
- * @returns A reference to the default value
- */
- [[nodiscard]] const Type& GetDefault() const {
- return default_value;
- }
-
- /**
- * Returns the label this setting was created with.
- *
- * @returns A reference to the label
- */
- [[nodiscard]] const std::string& GetLabel() const override {
- return label;
- }
-
- /**
- * Returns the setting's category AKA INI group.
- *
- * @returns The setting's category
- */
- [[nodiscard]] enum Category Category() const override {
- return category;
- }
-
- [[nodiscard]] bool RuntimeModfiable() const override {
- return runtime_modifiable;
- }
-
- [[nodiscard]] constexpr bool IsEnum() const override {
- return std::is_enum<Type>::value;
- }
-
- /**
- * Returns whether the current setting is Switchable.
- *
- * @returns If the setting is a SwitchableSetting
- */
- [[nodiscard]] virtual constexpr bool Switchable() const override {
- return false;
- }
-
-protected:
- std::string ToString(const Type& value_) const {
- if constexpr (std::is_same<Type, std::string>()) {
- return value_;
- } else if constexpr (std::is_same<Type, std::optional<u32>>()) {
- return value_.has_value() ? std::to_string(*value_) : "none";
- } else if constexpr (std::is_same<Type, bool>()) {
- return value_ ? "true" : "false";
- } else if (std::is_same<Type, AudioEngine>()) {
- return CanonicalizeEnum(value_);
- } else {
- return std::to_string(static_cast<u64>(value_));
- }
- }
-
-public:
- /**
- * Converts the value of the setting to a std::string. Respects the global state if the setting
- * has one.
- *
- * @returns The current setting as a std::string
- */
- std::string ToString() const override {
- return ToString(this->GetValue());
- }
-
- /**
- * Returns the default value of the setting as a std::string.
- *
- * @returns The default value as a string.
- */
- std::string DefaultToString() const override {
- return ToString(default_value);
- }
-
- /**
- * Assigns a value to the setting.
- *
- * @param val The desired setting value
- *
- * @returns A reference to the setting
- */
- virtual const Type& operator=(const Type& val) {
- Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
- std::swap(value, temp);
- return value;
- }
-
- /**
- * Returns a reference to the setting.
- *
- * @returns A reference to the setting
- */
- explicit virtual operator const Type&() const {
- return value;
- }
-
- /**
- * Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
- * thus respecting its constraints.
- *
- * @param input The desired value
- */
- void LoadString(const std::string& input) override {
- if (input.empty()) {
- this->SetValue(this->GetDefault());
- return;
- }
- try {
- if constexpr (std::is_same<Type, std::string>()) {
- this->SetValue(input);
- } else if constexpr (std::is_same<Type, std::optional<u32>>()) {
- this->SetValue(static_cast<u32>(std::stoul(input)));
- } else if constexpr (std::is_same<Type, bool>()) {
- this->SetValue(input == "true");
- } else if constexpr (std::is_same<Type, AudioEngine>()) {
- this->SetValue(ToEnum<Type>(input));
- } else {
- this->SetValue(static_cast<Type>(std::stoll(input)));
- }
- } catch (std::invalid_argument) {
- this->SetValue(this->GetDefault());
- }
- }
-
- [[nodiscard]] std::string constexpr Canonicalize() const override {
- if constexpr (std::is_enum<Type>::value) {
- return CanonicalizeEnum(this->GetValue());
- }
- return ToString(this->GetValue());
- }
-
- /**
- * Returns the save preference of the setting i.e. when saving or reading the setting from a
- * frontend, whether this setting should be skipped.
- *
- * @returns The save preference
- */
- virtual bool Save() const override {
- return save;
- }
-
- /**
- * Gives us another way to identify the setting without having to go through a string.
- *
- * @returns the type_index of the setting's type
- */
- virtual std::type_index TypeId() const override {
- return std::type_index(typeid(Type));
- }
-
- virtual constexpr u32 Id() const override {
- return id;
- }
-
- virtual std::string MinVal() const override {
- return this->ToString(minimum);
- }
- virtual std::string MaxVal() const override {
- return this->ToString(maximum);
- }
-
-protected:
- Type value{}; ///< The setting
- const Type default_value{}; ///< The default value
- const Type maximum{}; ///< Maximum allowed value of the setting
- const Type minimum{}; ///< Minimum allowed value of the setting
- const std::string label{}; ///< The setting's label
- const enum Category category; ///< The setting's category AKA INI group
- const u32 id;
- bool save;
- bool runtime_modifiable;
-};
-
-/**
- * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
- * custom setting to switch to when a guest application specifically requires it. The effect is that
- * other components of the emulator can access the setting's intended value without any need for the
- * component to ask whether the custom or global setting is needed at the moment.
- *
- * By default, the global setting is used.
- */
-template <typename Type, bool ranged = false>
-class SwitchableSetting : virtual public Setting<Type, ranged> {
-public:
- /**
- * Sets a default value, label, and setting value.
- *
- * @param linkage Setting registry
- * @param default_val Initial value of the setting, and default value of the setting
- * @param name Label for the setting
- * @param category_ Category of the setting AKA INI group
- */
- explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
- Category category, bool save = true, bool runtime_modifiable = false)
- requires(!ranged)
- : Setting<Type, false>{linkage, default_val, name, category, save, runtime_modifiable} {
- linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
- }
- virtual ~SwitchableSetting() = default;
-
- /**
- * Sets a default value, minimum value, maximum value, and label.
- *
- * @param linkage Setting registry
- * @param default_val Initial value of the setting, and default value of the setting
- * @param min_val Sets the minimum allowed value of the setting
- * @param max_val Sets the maximum allowed value of the setting
- * @param name Label for the setting
- * @param category_ Category of the setting AKA INI group
- */
- explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
- const Type& max_val, const std::string& name, Category category,
- bool save = true, bool runtime_modifiable = false)
- requires(ranged)
- : Setting<Type, true>{linkage, default_val, min_val, max_val,
- name, category, save, runtime_modifiable} {
- linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
- }
-
- /**
- * Tells this setting to represent either the global or custom setting when other member
- * functions are used.
- *
- * @param to_global Whether to use the global or custom setting.
- */
- void SetGlobal(bool to_global) override {
- use_global = to_global;
- }
-
- /**
- * Returns whether this setting is using the global setting or not.
- *
- * @returns The global state
- */
- [[nodiscard]] bool UsingGlobal() const override {
- return use_global;
- }
-
- /**
- * Returns either the global or custom setting depending on the values of this setting's global
- * state or if the global value was specifically requested.
- *
- * @param need_global Request global value regardless of setting's state; defaults to false
- *
- * @returns The required value of the setting
- */
- [[nodiscard]] virtual const Type& GetValue() const override {
- if (use_global) {
- return this->value;
- }
- return custom;
- }
- [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
- if (use_global || need_global) {
- return this->value;
- }
- return custom;
- }
-
- /**
- * Sets the current setting value depending on the global state.
- *
- * @param val The new value
- */
- void SetValue(const Type& val) override {
- Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
- if (use_global) {
- std::swap(this->value, temp);
- } else {
- std::swap(custom, temp);
- }
- }
-
- [[nodiscard]] virtual constexpr bool Switchable() const override {
- return true;
- }
-
- [[nodiscard]] virtual std::string ToStringGlobal() const override {
- return this->ToString(this->value);
- }
-
- /**
- * Assigns the current setting value depending on the global state.
- *
- * @param val The new value
- *
- * @returns A reference to the current setting value
- */
- const Type& operator=(const Type& val) override {
- Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
- if (use_global) {
- std::swap(this->value, temp);
- return this->value;
- }
- std::swap(custom, temp);
- return custom;
- }
-
- /**
- * Returns the current setting value depending on the global state.
- *
- * @returns A reference to the current setting value
- */
- virtual explicit operator const Type&() const override {
- if (use_global) {
- return this->value;
- }
- return custom;
- }
-
-protected:
- bool use_global{true}; ///< The setting's global state
- Type custom{}; ///< The custom value of the setting
-};
+// Instantiate the classes elsewhere (settings.cpp) to reduce compiler/linker work
+#define SETTING(TYPE, RANGED) extern template class Setting<TYPE, RANGED>
+#define SWITCHABLE(TYPE, RANGED) extern template class SwitchableSetting<TYPE, RANGED>
+
+SETTING(AudioEngine, false);
+SETTING(bool, false);
+SETTING(int, false);
+SETTING(s32, false);
+SETTING(std::string, false);
+SETTING(std::string, false);
+SETTING(u16, false);
+SWITCHABLE(AnisotropyMode, true);
+SWITCHABLE(AntiAliasing, false);
+SWITCHABLE(AspectRatio, true);
+SWITCHABLE(AstcDecodeMode, true);
+SWITCHABLE(AstcRecompression, true);
+SWITCHABLE(AudioMode, true);
+SWITCHABLE(CpuAccuracy, true);
+SWITCHABLE(FullscreenMode, true);
+SWITCHABLE(GpuAccuracy, true);
+SWITCHABLE(Language, true);
+SWITCHABLE(NvdecEmulation, false);
+SWITCHABLE(Region, true);
+SWITCHABLE(RendererBackend, true);
+SWITCHABLE(ScalingFilter, false);
+SWITCHABLE(ShaderBackend, true);
+SWITCHABLE(TimeZone, true);
+SETTING(VSyncMode, true);
+SWITCHABLE(bool, false);
+SWITCHABLE(int, false);
+SWITCHABLE(int, true);
+SWITCHABLE(s64, false);
+SWITCHABLE(u16, true);
+SWITCHABLE(u32, false);
+SWITCHABLE(u8, false);
+SWITCHABLE(u8, true);
+
+#undef SETTING
+#undef SWITCHABLE
/**
* The InputSetting class allows for getting a reference to either the global or custom members.
diff --git a/src/common/settings_common.h b/src/common/settings_common.h
new file mode 100644
index 000000000..93fddeba6
--- /dev/null
+++ b/src/common/settings_common.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <forward_list>
+#include <functional>
+#include <map>
+#include <string>
+#include <typeindex>
+#include "common/common_types.h"
+
+namespace Settings {
+
+enum class Category : u32 {
+ Audio,
+ Core,
+ Cpu,
+ CpuDebug,
+ CpuUnsafe,
+ Renderer,
+ RendererAdvanced,
+ RendererDebug,
+ System,
+ SystemAudio,
+ DataStorage,
+ Debugging,
+ DebuggingGraphics,
+ Miscellaneous,
+ Network,
+ WebService,
+ AddOns,
+ Controls,
+ Ui,
+ UiGeneral,
+ UiLayout,
+ UiGameList,
+ Screenshots,
+ Shortcuts,
+ Multiplayer,
+ Services,
+ Paths,
+ MaxEnum,
+};
+
+class BasicSetting {
+protected:
+ explicit BasicSetting() = default;
+
+public:
+ virtual ~BasicSetting() = default;
+
+ virtual Category Category() const = 0;
+ virtual constexpr bool Switchable() const = 0;
+ virtual std::string ToString() const = 0;
+ virtual std::string ToStringGlobal() const;
+ virtual void LoadString(const std::string& load) = 0;
+ virtual std::string Canonicalize() const = 0;
+ virtual const std::string& GetLabel() const = 0;
+ virtual std::string DefaultToString() const = 0;
+ virtual bool Save() const = 0;
+ virtual std::type_index TypeId() const = 0;
+ virtual constexpr bool IsEnum() const = 0;
+ virtual bool RuntimeModfiable() const = 0;
+ virtual void SetGlobal(bool global) {}
+ virtual constexpr u32 Id() const = 0;
+ virtual std::string MinVal() const = 0;
+ virtual std::string MaxVal() const = 0;
+ virtual bool UsingGlobal() const;
+};
+
+class Linkage {
+public:
+ explicit Linkage(u32 initial_count = 0);
+ ~Linkage();
+ std::map<Category, std::forward_list<BasicSetting*>> by_category{};
+ std::vector<std::function<void()>> restore_functions{};
+ u32 count;
+};
+
+} // namespace Settings
diff --git a/src/common/settings_setting.h b/src/common/settings_setting.h
new file mode 100644
index 000000000..f226e38d4
--- /dev/null
+++ b/src/common/settings_setting.h
@@ -0,0 +1,413 @@
+#pragma once
+
+#include <map>
+#include <optional>
+#include <string>
+#include <typeindex>
+#include <typeinfo>
+#include "common/common_types.h"
+#include "common/settings_common.h"
+#include "common/settings_enums.h"
+
+namespace Settings {
+
+/** The Setting class is a simple resource manager. It defines a label and default value
+ * alongside the actual value of the setting for simpler and less-error prone use with frontend
+ * configurations. Specifying a default value and label is required. A minimum and maximum range
+ * can be specified for sanitization.
+ */
+template <typename Type, bool ranged = false>
+class Setting : public BasicSetting {
+protected:
+ Setting() = default;
+
+ /**
+ * Only sets the setting to the given initializer, leaving the other members to their default
+ * initializers.
+ *
+ * @param global_val Initial value of the setting
+ */
+ explicit Setting(const Type& val)
+ : value{val},
+ default_value{}, maximum{}, minimum{}, label{}, category{Category::Miscellaneous}, id{} {}
+
+public:
+ /**
+ * Sets a default value, label, and setting value.
+ *
+ * @param linkage Setting registry
+ * @param default_val Initial value of the setting, and default value of the setting
+ * @param name Label for the setting
+ * @param category_ Category of the setting AKA INI group
+ */
+ explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
+ enum Category category_, bool save_ = true, bool runtime_modifiable_ = false)
+ requires(!ranged)
+ : value{default_val}, default_value{default_val}, label{name}, category{category_},
+ id{linkage.count}, save{save_}, runtime_modifiable{runtime_modifiable_} {
+ linkage.by_category[category].push_front(this);
+ linkage.count++;
+ }
+ virtual ~Setting() = default;
+
+ /**
+ * Sets a default value, minimum value, maximum value, and label.
+ *
+ * @param linkage Setting registry
+ * @param default_val Initial value of the setting, and default value of the setting
+ * @param min_val Sets the minimum allowed value of the setting
+ * @param max_val Sets the maximum allowed value of the setting
+ * @param name Label for the setting
+ * @param category_ Category of the setting AKA INI group
+ */
+ explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
+ const Type& max_val, const std::string& name, enum Category category_,
+ bool save_ = true, bool runtime_modifiable_ = false)
+ requires(ranged)
+ : value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val},
+ label{name}, category{category_}, id{linkage.count}, save{save_},
+ runtime_modifiable{runtime_modifiable_} {
+ linkage.by_category[category].push_front(this);
+ linkage.count++;
+ }
+
+ /**
+ * Returns a reference to the setting's value.
+ *
+ * @returns A reference to the setting
+ */
+ [[nodiscard]] virtual const Type& GetValue() const {
+ return value;
+ }
+
+ /**
+ * Sets the setting to the given value.
+ *
+ * @param val The desired value
+ */
+ virtual void SetValue(const Type& val) {
+ Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
+ std::swap(value, temp);
+ }
+
+ /**
+ * Returns the value that this setting was created with.
+ *
+ * @returns A reference to the default value
+ */
+ [[nodiscard]] const Type& GetDefault() const {
+ return default_value;
+ }
+
+ /**
+ * Returns the label this setting was created with.
+ *
+ * @returns A reference to the label
+ */
+ [[nodiscard]] const std::string& GetLabel() const override {
+ return label;
+ }
+
+ /**
+ * Returns the setting's category AKA INI group.
+ *
+ * @returns The setting's category
+ */
+ [[nodiscard]] enum Category Category() const override {
+ return category;
+ }
+
+ [[nodiscard]] bool RuntimeModfiable() const override {
+ return runtime_modifiable;
+ }
+
+ [[nodiscard]] constexpr bool IsEnum() const override {
+ return std::is_enum<Type>::value;
+ }
+
+ /**
+ * Returns whether the current setting is Switchable.
+ *
+ * @returns If the setting is a SwitchableSetting
+ */
+ [[nodiscard]] virtual constexpr bool Switchable() const override {
+ return false;
+ }
+
+protected:
+ std::string ToString(const Type& value_) const {
+ if constexpr (std::is_same<Type, std::string>()) {
+ return value_;
+ } else if constexpr (std::is_same<Type, std::optional<u32>>()) {
+ return value_.has_value() ? std::to_string(*value_) : "none";
+ } else if constexpr (std::is_same<Type, bool>()) {
+ return value_ ? "true" : "false";
+ } else if (std::is_same<Type, AudioEngine>()) {
+ return CanonicalizeEnum(value_);
+ } else {
+ return std::to_string(static_cast<u64>(value_));
+ }
+ }
+
+public:
+ /**
+ * Converts the value of the setting to a std::string. Respects the global state if the setting
+ * has one.
+ *
+ * @returns The current setting as a std::string
+ */
+ std::string ToString() const override {
+ return ToString(this->GetValue());
+ }
+
+ /**
+ * Returns the default value of the setting as a std::string.
+ *
+ * @returns The default value as a string.
+ */
+ std::string DefaultToString() const override {
+ return ToString(default_value);
+ }
+
+ /**
+ * Assigns a value to the setting.
+ *
+ * @param val The desired setting value
+ *
+ * @returns A reference to the setting
+ */
+ virtual const Type& operator=(const Type& val) {
+ Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
+ std::swap(value, temp);
+ return value;
+ }
+
+ /**
+ * Returns a reference to the setting.
+ *
+ * @returns A reference to the setting
+ */
+ explicit virtual operator const Type&() const {
+ return value;
+ }
+
+ /**
+ * Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
+ * thus respecting its constraints.
+ *
+ * @param input The desired value
+ */
+ void LoadString(const std::string& input) override {
+ if (input.empty()) {
+ this->SetValue(this->GetDefault());
+ return;
+ }
+ try {
+ if constexpr (std::is_same<Type, std::string>()) {
+ this->SetValue(input);
+ } else if constexpr (std::is_same<Type, std::optional<u32>>()) {
+ this->SetValue(static_cast<u32>(std::stoul(input)));
+ } else if constexpr (std::is_same<Type, bool>()) {
+ this->SetValue(input == "true");
+ } else if constexpr (std::is_same<Type, AudioEngine>()) {
+ this->SetValue(ToEnum<Type>(input));
+ } else {
+ this->SetValue(static_cast<Type>(std::stoll(input)));
+ }
+ } catch (std::invalid_argument) {
+ this->SetValue(this->GetDefault());
+ }
+ }
+
+ [[nodiscard]] std::string constexpr Canonicalize() const override {
+ if constexpr (std::is_enum<Type>::value) {
+ return CanonicalizeEnum(this->GetValue());
+ }
+ return ToString(this->GetValue());
+ }
+
+ /**
+ * Returns the save preference of the setting i.e. when saving or reading the setting from a
+ * frontend, whether this setting should be skipped.
+ *
+ * @returns The save preference
+ */
+ virtual bool Save() const override {
+ return save;
+ }
+
+ /**
+ * Gives us another way to identify the setting without having to go through a string.
+ *
+ * @returns the type_index of the setting's type
+ */
+ virtual std::type_index TypeId() const override {
+ return std::type_index(typeid(Type));
+ }
+
+ virtual constexpr u32 Id() const override {
+ return id;
+ }
+
+ virtual std::string MinVal() const override {
+ return this->ToString(minimum);
+ }
+ virtual std::string MaxVal() const override {
+ return this->ToString(maximum);
+ }
+
+protected:
+ Type value{}; ///< The setting
+ const Type default_value{}; ///< The default value
+ const Type maximum{}; ///< Maximum allowed value of the setting
+ const Type minimum{}; ///< Minimum allowed value of the setting
+ const std::string label{}; ///< The setting's label
+ const enum Category category; ///< The setting's category AKA INI group
+ const u32 id;
+ bool save;
+ bool runtime_modifiable;
+};
+
+/**
+ * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
+ * custom setting to switch to when a guest application specifically requires it. The effect is that
+ * other components of the emulator can access the setting's intended value without any need for the
+ * component to ask whether the custom or global setting is needed at the moment.
+ *
+ * By default, the global setting is used.
+ */
+template <typename Type, bool ranged = false>
+class SwitchableSetting : virtual public Setting<Type, ranged> {
+public:
+ /**
+ * Sets a default value, label, and setting value.
+ *
+ * @param linkage Setting registry
+ * @param default_val Initial value of the setting, and default value of the setting
+ * @param name Label for the setting
+ * @param category_ Category of the setting AKA INI group
+ */
+ explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
+ Category category, bool save = true, bool runtime_modifiable = false)
+ requires(!ranged)
+ : Setting<Type, false>{linkage, default_val, name, category, save, runtime_modifiable} {
+ linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
+ }
+ virtual ~SwitchableSetting() = default;
+
+ /**
+ * Sets a default value, minimum value, maximum value, and label.
+ *
+ * @param linkage Setting registry
+ * @param default_val Initial value of the setting, and default value of the setting
+ * @param min_val Sets the minimum allowed value of the setting
+ * @param max_val Sets the maximum allowed value of the setting
+ * @param name Label for the setting
+ * @param category_ Category of the setting AKA INI group
+ */
+ explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
+ const Type& max_val, const std::string& name, Category category,
+ bool save = true, bool runtime_modifiable = false)
+ requires(ranged)
+ : Setting<Type, true>{linkage, default_val, min_val, max_val,
+ name, category, save, runtime_modifiable} {
+ linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
+ }
+
+ /**
+ * Tells this setting to represent either the global or custom setting when other member
+ * functions are used.
+ *
+ * @param to_global Whether to use the global or custom setting.
+ */
+ void SetGlobal(bool to_global) override {
+ use_global = to_global;
+ }
+
+ /**
+ * Returns whether this setting is using the global setting or not.
+ *
+ * @returns The global state
+ */
+ [[nodiscard]] bool UsingGlobal() const override {
+ return use_global;
+ }
+
+ /**
+ * Returns either the global or custom setting depending on the values of this setting's global
+ * state or if the global value was specifically requested.
+ *
+ * @param need_global Request global value regardless of setting's state; defaults to false
+ *
+ * @returns The required value of the setting
+ */
+ [[nodiscard]] virtual const Type& GetValue() const override {
+ if (use_global) {
+ return this->value;
+ }
+ return custom;
+ }
+ [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
+ if (use_global || need_global) {
+ return this->value;
+ }
+ return custom;
+ }
+
+ /**
+ * Sets the current setting value depending on the global state.
+ *
+ * @param val The new value
+ */
+ void SetValue(const Type& val) override {
+ Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
+ if (use_global) {
+ std::swap(this->value, temp);
+ } else {
+ std::swap(custom, temp);
+ }
+ }
+
+ [[nodiscard]] virtual constexpr bool Switchable() const override {
+ return true;
+ }
+
+ [[nodiscard]] virtual std::string ToStringGlobal() const override {
+ return this->ToString(this->value);
+ }
+
+ /**
+ * Assigns the current setting value depending on the global state.
+ *
+ * @param val The new value
+ *
+ * @returns A reference to the current setting value
+ */
+ const Type& operator=(const Type& val) override {
+ Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
+ if (use_global) {
+ std::swap(this->value, temp);
+ return this->value;
+ }
+ std::swap(custom, temp);
+ return custom;
+ }
+
+ /**
+ * Returns the current setting value depending on the global state.
+ *
+ * @returns A reference to the current setting value
+ */
+ virtual explicit operator const Type&() const override {
+ if (use_global) {
+ return this->value;
+ }
+ return custom;
+ }
+
+protected:
+ bool use_global{true}; ///< The setting's global state
+ Type custom{}; ///< The custom value of the setting
+};
+
+} // namespace Settings