summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/sink/sink_details.h5
-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
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/shared_widget.cpp3
-rw-r--r--src/yuzu/uisettings.cpp10
-rw-r--r--src/yuzu/uisettings.h10
10 files changed, 615 insertions, 477 deletions
diff --git a/src/audio_core/sink/sink_details.h b/src/audio_core/sink/sink_details.h
index 44403db71..c8498842b 100644
--- a/src/audio_core/sink/sink_details.h
+++ b/src/audio_core/sink/sink_details.h
@@ -3,13 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <memory>
6#include <string> 7#include <string>
7#include <string_view> 8#include <string_view>
8#include <vector> 9#include <vector>
10#include "common/settings_enums.h"
9 11
10namespace Settings {
11enum class AudioEngine : u32;
12}
13namespace AudioCore { 12namespace AudioCore {
14class AudioManager; 13class AudioManager;
15 14
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
110 scratch_buffer.h 110 scratch_buffer.h
111 settings.cpp 111 settings.cpp
112 settings.h 112 settings.h
113 settings_common.h
113 settings_enums.h 114 settings_enums.h
114 settings_input.cpp 115 settings_input.cpp
115 settings_input.h 116 settings_input.h
117 settings_setting.h
116 socket_types.h 118 socket_types.h
117 spin_lock.cpp 119 spin_lock.cpp
118 spin_lock.h 120 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 @@
7#include <exception> 7#include <exception>
8#include <stdexcept> 8#include <stdexcept>
9#endif 9#endif
10#include <compare>
11#include <cstddef>
12#include <filesystem>
13#include <forward_list>
10#include <functional> 14#include <functional>
11#include <string_view> 15#include <string_view>
16#include <type_traits>
17#include <fmt/core.h>
12 18
13#include "common/assert.h" 19#include "common/assert.h"
20#include "common/fs/fs_util.h"
14#include "common/fs/path_util.h" 21#include "common/fs/path_util.h"
15#include "common/logging/log.h" 22#include "common/logging/log.h"
16#include "common/settings.h" 23#include "common/settings.h"
@@ -18,6 +25,43 @@
18 25
19namespace Settings { 26namespace Settings {
20 27
28#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
29#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
30
31SETTING(AudioEngine, false);
32SETTING(bool, false);
33SETTING(int, false);
34SETTING(std::string, false);
35SETTING(u16, false);
36SWITCHABLE(AnisotropyMode, true);
37SWITCHABLE(AntiAliasing, false);
38SWITCHABLE(AspectRatio, true);
39SWITCHABLE(AstcDecodeMode, true);
40SWITCHABLE(AstcRecompression, true);
41SWITCHABLE(AudioMode, true);
42SWITCHABLE(CpuAccuracy, true);
43SWITCHABLE(FullscreenMode, true);
44SWITCHABLE(GpuAccuracy, true);
45SWITCHABLE(Language, true);
46SWITCHABLE(NvdecEmulation, false);
47SWITCHABLE(Region, true);
48SWITCHABLE(RendererBackend, true);
49SWITCHABLE(ScalingFilter, false);
50SWITCHABLE(ShaderBackend, true);
51SWITCHABLE(TimeZone, true);
52SETTING(VSyncMode, true);
53SWITCHABLE(bool, false);
54SWITCHABLE(int, false);
55SWITCHABLE(int, true);
56SWITCHABLE(s64, false);
57SWITCHABLE(u16, true);
58SWITCHABLE(u32, false);
59SWITCHABLE(u8, false);
60SWITCHABLE(u8, true);
61
62#undef SETTING
63#undef SWITCHABLE
64
21Values values; 65Values values;
22static bool configuring_global = true; 66static bool configuring_global = true;
23 67
@@ -238,6 +282,14 @@ void UpdateRescalingInfo() {
238 info.active = info.up_scale != 1 || info.down_shift != 0; 282 info.active = info.up_scale != 1 || info.down_shift != 0;
239} 283}
240 284
285std::string BasicSetting::ToStringGlobal() const {
286 return {};
287}
288
289bool BasicSetting::UsingGlobal() const {
290 return true;
291}
292
241void RestoreGlobalState(bool is_powered_on) { 293void RestoreGlobalState(bool is_powered_on) {
242 // If a game is running, DO NOT restore the global settings state 294 // If a game is running, DO NOT restore the global settings state
243 if (is_powered_on) { 295 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 @@
5 5
6#include <algorithm> 6#include <algorithm>
7#include <array> 7#include <array>
8#include <forward_list>
9#include <functional>
10#include <map> 8#include <map>
11#include <optional> 9#include <memory>
12#include <stdexcept> 10#include <stdexcept>
13#include <string> 11#include <string>
14#include <typeindex>
15#include <typeinfo>
16#include <utility> 12#include <utility>
17#include <vector> 13#include <vector>
18 14
19#include "common/common_types.h" 15#include "common/common_types.h"
16#include "common/settings_common.h"
20#include "common/settings_enums.h" 17#include "common/settings_enums.h"
21#include "common/settings_input.h" 18#include "common/settings_input.h"
19#include "common/settings_setting.h"
22 20
23namespace Settings { 21namespace Settings {
24 22
25enum class Category : u32 {
26 Audio,
27 Core,
28 Cpu,
29 CpuDebug,
30 CpuUnsafe,
31 Renderer,
32 RendererAdvanced,
33 RendererDebug,
34 System,
35 SystemAudio,
36 DataStorage,
37 Debugging,
38 DebuggingGraphics,
39 Miscellaneous,
40 Network,
41 WebService,
42 AddOns,
43 Controls,
44 Ui,
45 UiGeneral,
46 UiLayout,
47 UiGameList,
48 Screenshots,
49 Shortcuts,
50 Multiplayer,
51 Services,
52 Paths,
53 MaxEnum,
54};
55
56const char* TranslateCategory(Settings::Category category); 23const char* TranslateCategory(Settings::Category category);
57 24
58struct ResolutionScalingInfo { 25struct ResolutionScalingInfo {
@@ -78,441 +45,45 @@ struct ResolutionScalingInfo {
78 } 45 }
79}; 46};
80 47
81class BasicSetting { 48// Instantiate the classes elsewhere (settings.cpp) to reduce compiler/linker work
82protected: 49#define SETTING(TYPE, RANGED) extern template class Setting<TYPE, RANGED>
83 explicit BasicSetting() = default; 50#define SWITCHABLE(TYPE, RANGED) extern template class SwitchableSetting<TYPE, RANGED>
84 51
85public: 52SETTING(AudioEngine, false);
86 virtual ~BasicSetting() = default; 53SETTING(bool, false);
87 54SETTING(int, false);
88 virtual Category Category() const = 0; 55SETTING(s32, false);
89 virtual constexpr bool Switchable() const = 0; 56SETTING(std::string, false);
90 virtual std::string ToString() const = 0; 57SETTING(std::string, false);
91 virtual std::string ToStringGlobal() const { 58SETTING(u16, false);
92 return {}; 59SWITCHABLE(AnisotropyMode, true);
93 } 60SWITCHABLE(AntiAliasing, false);
94 virtual void LoadString(const std::string& load) = 0; 61SWITCHABLE(AspectRatio, true);
95 virtual std::string Canonicalize() const = 0; 62SWITCHABLE(AstcDecodeMode, true);
96 virtual const std::string& GetLabel() const = 0; 63SWITCHABLE(AstcRecompression, true);
97 virtual std::string DefaultToString() const = 0; 64SWITCHABLE(AudioMode, true);
98 virtual bool Save() const = 0; 65SWITCHABLE(CpuAccuracy, true);
99 virtual std::type_index TypeId() const = 0; 66SWITCHABLE(FullscreenMode, true);
100 virtual constexpr bool IsEnum() const = 0; 67SWITCHABLE(GpuAccuracy, true);
101 virtual bool RuntimeModfiable() const = 0; 68SWITCHABLE(Language, true);
102 virtual void SetGlobal(bool global) {} 69SWITCHABLE(NvdecEmulation, false);
103 virtual constexpr u32 Id() const = 0; 70SWITCHABLE(Region, true);
104 virtual std::string MinVal() const = 0; 71SWITCHABLE(RendererBackend, true);
105 virtual std::string MaxVal() const = 0; 72SWITCHABLE(ScalingFilter, false);
106 virtual bool UsingGlobal() const { 73SWITCHABLE(ShaderBackend, true);
107 return true; 74SWITCHABLE(TimeZone, true);
108 } 75SETTING(VSyncMode, true);
109}; 76SWITCHABLE(bool, false);
110 77SWITCHABLE(int, false);
111class Linkage { 78SWITCHABLE(int, true);
112public: 79SWITCHABLE(s64, false);
113 explicit Linkage(u32 initial_count = 0); 80SWITCHABLE(u16, true);
114 ~Linkage(); 81SWITCHABLE(u32, false);
115 std::map<Category, std::forward_list<BasicSetting*>> by_category{}; 82SWITCHABLE(u8, false);
116 std::vector<std::function<void()>> restore_functions{}; 83SWITCHABLE(u8, true);
117 u32 count; 84
118}; 85#undef SETTING
119 86#undef SWITCHABLE
120/** The Setting class is a simple resource manager. It defines a label and default value
121 * alongside the actual value of the setting for simpler and less-error prone use with frontend
122 * configurations. Specifying a default value and label is required. A minimum and maximum range
123 * can be specified for sanitization.
124 */
125template <typename Type, bool ranged = false>
126class Setting : public BasicSetting {
127protected:
128 Setting() = default;
129
130 /**
131 * Only sets the setting to the given initializer, leaving the other members to their default
132 * initializers.
133 *
134 * @param global_val Initial value of the setting
135 */
136 explicit Setting(const Type& val) : value{val} {}
137
138public:
139 /**
140 * Sets a default value, label, and setting value.
141 *
142 * @param linkage Setting registry
143 * @param default_val Initial value of the setting, and default value of the setting
144 * @param name Label for the setting
145 * @param category_ Category of the setting AKA INI group
146 */
147 explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
148 enum Category category_, bool save_ = true, bool runtime_modifiable_ = false)
149 requires(!ranged)
150 : value{default_val}, default_value{default_val}, label{name}, category{category_},
151 id{linkage.count}, save{save_}, runtime_modifiable{runtime_modifiable_} {
152 linkage.by_category[category].push_front(this);
153 linkage.count++;
154 }
155 virtual ~Setting() = default;
156
157 /**
158 * Sets a default value, minimum value, maximum value, and label.
159 *
160 * @param linkage Setting registry
161 * @param default_val Initial value of the setting, and default value of the setting
162 * @param min_val Sets the minimum allowed value of the setting
163 * @param max_val Sets the maximum allowed value of the setting
164 * @param name Label for the setting
165 * @param category_ Category of the setting AKA INI group
166 */
167 explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
168 const Type& max_val, const std::string& name, enum Category category_,
169 bool save_ = true, bool runtime_modifiable_ = false)
170 requires(ranged)
171 : value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val},
172 label{name}, category{category_}, id{linkage.count}, save{save_},
173 runtime_modifiable{runtime_modifiable_} {
174 linkage.by_category[category].push_front(this);
175 linkage.count++;
176 }
177
178 /**
179 * Returns a reference to the setting's value.
180 *
181 * @returns A reference to the setting
182 */
183 [[nodiscard]] virtual const Type& GetValue() const {
184 return value;
185 }
186
187 /**
188 * Sets the setting to the given value.
189 *
190 * @param val The desired value
191 */
192 virtual void SetValue(const Type& val) {
193 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
194 std::swap(value, temp);
195 }
196
197 /**
198 * Returns the value that this setting was created with.
199 *
200 * @returns A reference to the default value
201 */
202 [[nodiscard]] const Type& GetDefault() const {
203 return default_value;
204 }
205
206 /**
207 * Returns the label this setting was created with.
208 *
209 * @returns A reference to the label
210 */
211 [[nodiscard]] const std::string& GetLabel() const override {
212 return label;
213 }
214
215 /**
216 * Returns the setting's category AKA INI group.
217 *
218 * @returns The setting's category
219 */
220 [[nodiscard]] enum Category Category() const override {
221 return category;
222 }
223
224 [[nodiscard]] bool RuntimeModfiable() const override {
225 return runtime_modifiable;
226 }
227
228 [[nodiscard]] constexpr bool IsEnum() const override {
229 return std::is_enum<Type>::value;
230 }
231
232 /**
233 * Returns whether the current setting is Switchable.
234 *
235 * @returns If the setting is a SwitchableSetting
236 */
237 [[nodiscard]] virtual constexpr bool Switchable() const override {
238 return false;
239 }
240
241protected:
242 std::string ToString(const Type& value_) const {
243 if constexpr (std::is_same<Type, std::string>()) {
244 return value_;
245 } else if constexpr (std::is_same<Type, std::optional<u32>>()) {
246 return value_.has_value() ? std::to_string(*value_) : "none";
247 } else if constexpr (std::is_same<Type, bool>()) {
248 return value_ ? "true" : "false";
249 } else if (std::is_same<Type, AudioEngine>()) {
250 return CanonicalizeEnum(value_);
251 } else {
252 return std::to_string(static_cast<u64>(value_));
253 }
254 }
255
256public:
257 /**
258 * Converts the value of the setting to a std::string. Respects the global state if the setting
259 * has one.
260 *
261 * @returns The current setting as a std::string
262 */
263 std::string ToString() const override {
264 return ToString(this->GetValue());
265 }
266
267 /**
268 * Returns the default value of the setting as a std::string.
269 *
270 * @returns The default value as a string.
271 */
272 std::string DefaultToString() const override {
273 return ToString(default_value);
274 }
275
276 /**
277 * Assigns a value to the setting.
278 *
279 * @param val The desired setting value
280 *
281 * @returns A reference to the setting
282 */
283 virtual const Type& operator=(const Type& val) {
284 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
285 std::swap(value, temp);
286 return value;
287 }
288
289 /**
290 * Returns a reference to the setting.
291 *
292 * @returns A reference to the setting
293 */
294 explicit virtual operator const Type&() const {
295 return value;
296 }
297
298 /**
299 * Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
300 * thus respecting its constraints.
301 *
302 * @param input The desired value
303 */
304 void LoadString(const std::string& input) override {
305 if (input.empty()) {
306 this->SetValue(this->GetDefault());
307 return;
308 }
309 try {
310 if constexpr (std::is_same<Type, std::string>()) {
311 this->SetValue(input);
312 } else if constexpr (std::is_same<Type, std::optional<u32>>()) {
313 this->SetValue(static_cast<u32>(std::stoul(input)));
314 } else if constexpr (std::is_same<Type, bool>()) {
315 this->SetValue(input == "true");
316 } else if constexpr (std::is_same<Type, AudioEngine>()) {
317 this->SetValue(ToEnum<Type>(input));
318 } else {
319 this->SetValue(static_cast<Type>(std::stoll(input)));
320 }
321 } catch (std::invalid_argument) {
322 this->SetValue(this->GetDefault());
323 }
324 }
325
326 [[nodiscard]] std::string constexpr Canonicalize() const override {
327 if constexpr (std::is_enum<Type>::value) {
328 return CanonicalizeEnum(this->GetValue());
329 }
330 return ToString(this->GetValue());
331 }
332
333 /**
334 * Returns the save preference of the setting i.e. when saving or reading the setting from a
335 * frontend, whether this setting should be skipped.
336 *
337 * @returns The save preference
338 */
339 virtual bool Save() const override {
340 return save;
341 }
342
343 /**
344 * Gives us another way to identify the setting without having to go through a string.
345 *
346 * @returns the type_index of the setting's type
347 */
348 virtual std::type_index TypeId() const override {
349 return std::type_index(typeid(Type));
350 }
351
352 virtual constexpr u32 Id() const override {
353 return id;
354 }
355
356 virtual std::string MinVal() const override {
357 return this->ToString(minimum);
358 }
359 virtual std::string MaxVal() const override {
360 return this->ToString(maximum);
361 }
362
363protected:
364 Type value{}; ///< The setting
365 const Type default_value{}; ///< The default value
366 const Type maximum{}; ///< Maximum allowed value of the setting
367 const Type minimum{}; ///< Minimum allowed value of the setting
368 const std::string label{}; ///< The setting's label
369 const enum Category category; ///< The setting's category AKA INI group
370 const u32 id;
371 bool save;
372 bool runtime_modifiable;
373};
374
375/**
376 * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
377 * custom setting to switch to when a guest application specifically requires it. The effect is that
378 * other components of the emulator can access the setting's intended value without any need for the
379 * component to ask whether the custom or global setting is needed at the moment.
380 *
381 * By default, the global setting is used.
382 */
383template <typename Type, bool ranged = false>
384class SwitchableSetting : virtual public Setting<Type, ranged> {
385public:
386 /**
387 * Sets a default value, label, and setting value.
388 *
389 * @param linkage Setting registry
390 * @param default_val Initial value of the setting, and default value of the setting
391 * @param name Label for the setting
392 * @param category_ Category of the setting AKA INI group
393 */
394 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
395 Category category, bool save = true, bool runtime_modifiable = false)
396 requires(!ranged)
397 : Setting<Type, false>{linkage, default_val, name, category, save, runtime_modifiable} {
398 linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
399 }
400 virtual ~SwitchableSetting() = default;
401
402 /**
403 * Sets a default value, minimum value, maximum value, and label.
404 *
405 * @param linkage Setting registry
406 * @param default_val Initial value of the setting, and default value of the setting
407 * @param min_val Sets the minimum allowed value of the setting
408 * @param max_val Sets the maximum allowed value of the setting
409 * @param name Label for the setting
410 * @param category_ Category of the setting AKA INI group
411 */
412 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
413 const Type& max_val, const std::string& name, Category category,
414 bool save = true, bool runtime_modifiable = false)
415 requires(ranged)
416 : Setting<Type, true>{linkage, default_val, min_val, max_val,
417 name, category, save, runtime_modifiable} {
418 linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
419 }
420
421 /**
422 * Tells this setting to represent either the global or custom setting when other member
423 * functions are used.
424 *
425 * @param to_global Whether to use the global or custom setting.
426 */
427 void SetGlobal(bool to_global) override {
428 use_global = to_global;
429 }
430
431 /**
432 * Returns whether this setting is using the global setting or not.
433 *
434 * @returns The global state
435 */
436 [[nodiscard]] bool UsingGlobal() const override {
437 return use_global;
438 }
439
440 /**
441 * Returns either the global or custom setting depending on the values of this setting's global
442 * state or if the global value was specifically requested.
443 *
444 * @param need_global Request global value regardless of setting's state; defaults to false
445 *
446 * @returns The required value of the setting
447 */
448 [[nodiscard]] virtual const Type& GetValue() const override {
449 if (use_global) {
450 return this->value;
451 }
452 return custom;
453 }
454 [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
455 if (use_global || need_global) {
456 return this->value;
457 }
458 return custom;
459 }
460
461 /**
462 * Sets the current setting value depending on the global state.
463 *
464 * @param val The new value
465 */
466 void SetValue(const Type& val) override {
467 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
468 if (use_global) {
469 std::swap(this->value, temp);
470 } else {
471 std::swap(custom, temp);
472 }
473 }
474
475 [[nodiscard]] virtual constexpr bool Switchable() const override {
476 return true;
477 }
478
479 [[nodiscard]] virtual std::string ToStringGlobal() const override {
480 return this->ToString(this->value);
481 }
482
483 /**
484 * Assigns the current setting value depending on the global state.
485 *
486 * @param val The new value
487 *
488 * @returns A reference to the current setting value
489 */
490 const Type& operator=(const Type& val) override {
491 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
492 if (use_global) {
493 std::swap(this->value, temp);
494 return this->value;
495 }
496 std::swap(custom, temp);
497 return custom;
498 }
499
500 /**
501 * Returns the current setting value depending on the global state.
502 *
503 * @returns A reference to the current setting value
504 */
505 virtual explicit operator const Type&() const override {
506 if (use_global) {
507 return this->value;
508 }
509 return custom;
510 }
511
512protected:
513 bool use_global{true}; ///< The setting's global state
514 Type custom{}; ///< The custom value of the setting
515};
516 87
517/** 88/**
518 * The InputSetting class allows for getting a reference to either the global or custom members. 89 * 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 @@
1#pragma once
2
3#include <forward_list>
4#include <functional>
5#include <map>
6#include <string>
7#include <typeindex>
8#include "common/common_types.h"
9
10namespace Settings {
11
12enum class Category : u32 {
13 Audio,
14 Core,
15 Cpu,
16 CpuDebug,
17 CpuUnsafe,
18 Renderer,
19 RendererAdvanced,
20 RendererDebug,
21 System,
22 SystemAudio,
23 DataStorage,
24 Debugging,
25 DebuggingGraphics,
26 Miscellaneous,
27 Network,
28 WebService,
29 AddOns,
30 Controls,
31 Ui,
32 UiGeneral,
33 UiLayout,
34 UiGameList,
35 Screenshots,
36 Shortcuts,
37 Multiplayer,
38 Services,
39 Paths,
40 MaxEnum,
41};
42
43class BasicSetting {
44protected:
45 explicit BasicSetting() = default;
46
47public:
48 virtual ~BasicSetting() = default;
49
50 virtual Category Category() const = 0;
51 virtual constexpr bool Switchable() const = 0;
52 virtual std::string ToString() const = 0;
53 virtual std::string ToStringGlobal() const;
54 virtual void LoadString(const std::string& load) = 0;
55 virtual std::string Canonicalize() const = 0;
56 virtual const std::string& GetLabel() const = 0;
57 virtual std::string DefaultToString() const = 0;
58 virtual bool Save() const = 0;
59 virtual std::type_index TypeId() const = 0;
60 virtual constexpr bool IsEnum() const = 0;
61 virtual bool RuntimeModfiable() const = 0;
62 virtual void SetGlobal(bool global) {}
63 virtual constexpr u32 Id() const = 0;
64 virtual std::string MinVal() const = 0;
65 virtual std::string MaxVal() const = 0;
66 virtual bool UsingGlobal() const;
67};
68
69class Linkage {
70public:
71 explicit Linkage(u32 initial_count = 0);
72 ~Linkage();
73 std::map<Category, std::forward_list<BasicSetting*>> by_category{};
74 std::vector<std::function<void()>> restore_functions{};
75 u32 count;
76};
77
78} // 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 @@
1#pragma once
2
3#include <map>
4#include <optional>
5#include <string>
6#include <typeindex>
7#include <typeinfo>
8#include "common/common_types.h"
9#include "common/settings_common.h"
10#include "common/settings_enums.h"
11
12namespace Settings {
13
14/** The Setting class is a simple resource manager. It defines a label and default value
15 * alongside the actual value of the setting for simpler and less-error prone use with frontend
16 * configurations. Specifying a default value and label is required. A minimum and maximum range
17 * can be specified for sanitization.
18 */
19template <typename Type, bool ranged = false>
20class Setting : public BasicSetting {
21protected:
22 Setting() = default;
23
24 /**
25 * Only sets the setting to the given initializer, leaving the other members to their default
26 * initializers.
27 *
28 * @param global_val Initial value of the setting
29 */
30 explicit Setting(const Type& val)
31 : value{val},
32 default_value{}, maximum{}, minimum{}, label{}, category{Category::Miscellaneous}, id{} {}
33
34public:
35 /**
36 * Sets a default value, label, and setting value.
37 *
38 * @param linkage Setting registry
39 * @param default_val Initial value of the setting, and default value of the setting
40 * @param name Label for the setting
41 * @param category_ Category of the setting AKA INI group
42 */
43 explicit Setting(Linkage& linkage, const Type& default_val, const std::string& name,
44 enum Category category_, bool save_ = true, bool runtime_modifiable_ = false)
45 requires(!ranged)
46 : value{default_val}, default_value{default_val}, label{name}, category{category_},
47 id{linkage.count}, save{save_}, runtime_modifiable{runtime_modifiable_} {
48 linkage.by_category[category].push_front(this);
49 linkage.count++;
50 }
51 virtual ~Setting() = default;
52
53 /**
54 * Sets a default value, minimum value, maximum value, and label.
55 *
56 * @param linkage Setting registry
57 * @param default_val Initial value of the setting, and default value of the setting
58 * @param min_val Sets the minimum allowed value of the setting
59 * @param max_val Sets the maximum allowed value of the setting
60 * @param name Label for the setting
61 * @param category_ Category of the setting AKA INI group
62 */
63 explicit Setting(Linkage& linkage, const Type& default_val, const Type& min_val,
64 const Type& max_val, const std::string& name, enum Category category_,
65 bool save_ = true, bool runtime_modifiable_ = false)
66 requires(ranged)
67 : value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val},
68 label{name}, category{category_}, id{linkage.count}, save{save_},
69 runtime_modifiable{runtime_modifiable_} {
70 linkage.by_category[category].push_front(this);
71 linkage.count++;
72 }
73
74 /**
75 * Returns a reference to the setting's value.
76 *
77 * @returns A reference to the setting
78 */
79 [[nodiscard]] virtual const Type& GetValue() const {
80 return value;
81 }
82
83 /**
84 * Sets the setting to the given value.
85 *
86 * @param val The desired value
87 */
88 virtual void SetValue(const Type& val) {
89 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
90 std::swap(value, temp);
91 }
92
93 /**
94 * Returns the value that this setting was created with.
95 *
96 * @returns A reference to the default value
97 */
98 [[nodiscard]] const Type& GetDefault() const {
99 return default_value;
100 }
101
102 /**
103 * Returns the label this setting was created with.
104 *
105 * @returns A reference to the label
106 */
107 [[nodiscard]] const std::string& GetLabel() const override {
108 return label;
109 }
110
111 /**
112 * Returns the setting's category AKA INI group.
113 *
114 * @returns The setting's category
115 */
116 [[nodiscard]] enum Category Category() const override {
117 return category;
118 }
119
120 [[nodiscard]] bool RuntimeModfiable() const override {
121 return runtime_modifiable;
122 }
123
124 [[nodiscard]] constexpr bool IsEnum() const override {
125 return std::is_enum<Type>::value;
126 }
127
128 /**
129 * Returns whether the current setting is Switchable.
130 *
131 * @returns If the setting is a SwitchableSetting
132 */
133 [[nodiscard]] virtual constexpr bool Switchable() const override {
134 return false;
135 }
136
137protected:
138 std::string ToString(const Type& value_) const {
139 if constexpr (std::is_same<Type, std::string>()) {
140 return value_;
141 } else if constexpr (std::is_same<Type, std::optional<u32>>()) {
142 return value_.has_value() ? std::to_string(*value_) : "none";
143 } else if constexpr (std::is_same<Type, bool>()) {
144 return value_ ? "true" : "false";
145 } else if (std::is_same<Type, AudioEngine>()) {
146 return CanonicalizeEnum(value_);
147 } else {
148 return std::to_string(static_cast<u64>(value_));
149 }
150 }
151
152public:
153 /**
154 * Converts the value of the setting to a std::string. Respects the global state if the setting
155 * has one.
156 *
157 * @returns The current setting as a std::string
158 */
159 std::string ToString() const override {
160 return ToString(this->GetValue());
161 }
162
163 /**
164 * Returns the default value of the setting as a std::string.
165 *
166 * @returns The default value as a string.
167 */
168 std::string DefaultToString() const override {
169 return ToString(default_value);
170 }
171
172 /**
173 * Assigns a value to the setting.
174 *
175 * @param val The desired setting value
176 *
177 * @returns A reference to the setting
178 */
179 virtual const Type& operator=(const Type& val) {
180 Type temp{ranged ? std::clamp(val, minimum, maximum) : val};
181 std::swap(value, temp);
182 return value;
183 }
184
185 /**
186 * Returns a reference to the setting.
187 *
188 * @returns A reference to the setting
189 */
190 explicit virtual operator const Type&() const {
191 return value;
192 }
193
194 /**
195 * Converts the given value to the Setting's type of value. Uses SetValue to enter the setting,
196 * thus respecting its constraints.
197 *
198 * @param input The desired value
199 */
200 void LoadString(const std::string& input) override {
201 if (input.empty()) {
202 this->SetValue(this->GetDefault());
203 return;
204 }
205 try {
206 if constexpr (std::is_same<Type, std::string>()) {
207 this->SetValue(input);
208 } else if constexpr (std::is_same<Type, std::optional<u32>>()) {
209 this->SetValue(static_cast<u32>(std::stoul(input)));
210 } else if constexpr (std::is_same<Type, bool>()) {
211 this->SetValue(input == "true");
212 } else if constexpr (std::is_same<Type, AudioEngine>()) {
213 this->SetValue(ToEnum<Type>(input));
214 } else {
215 this->SetValue(static_cast<Type>(std::stoll(input)));
216 }
217 } catch (std::invalid_argument) {
218 this->SetValue(this->GetDefault());
219 }
220 }
221
222 [[nodiscard]] std::string constexpr Canonicalize() const override {
223 if constexpr (std::is_enum<Type>::value) {
224 return CanonicalizeEnum(this->GetValue());
225 }
226 return ToString(this->GetValue());
227 }
228
229 /**
230 * Returns the save preference of the setting i.e. when saving or reading the setting from a
231 * frontend, whether this setting should be skipped.
232 *
233 * @returns The save preference
234 */
235 virtual bool Save() const override {
236 return save;
237 }
238
239 /**
240 * Gives us another way to identify the setting without having to go through a string.
241 *
242 * @returns the type_index of the setting's type
243 */
244 virtual std::type_index TypeId() const override {
245 return std::type_index(typeid(Type));
246 }
247
248 virtual constexpr u32 Id() const override {
249 return id;
250 }
251
252 virtual std::string MinVal() const override {
253 return this->ToString(minimum);
254 }
255 virtual std::string MaxVal() const override {
256 return this->ToString(maximum);
257 }
258
259protected:
260 Type value{}; ///< The setting
261 const Type default_value{}; ///< The default value
262 const Type maximum{}; ///< Maximum allowed value of the setting
263 const Type minimum{}; ///< Minimum allowed value of the setting
264 const std::string label{}; ///< The setting's label
265 const enum Category category; ///< The setting's category AKA INI group
266 const u32 id;
267 bool save;
268 bool runtime_modifiable;
269};
270
271/**
272 * The SwitchableSetting class is a slightly more complex version of the Setting class. This adds a
273 * custom setting to switch to when a guest application specifically requires it. The effect is that
274 * other components of the emulator can access the setting's intended value without any need for the
275 * component to ask whether the custom or global setting is needed at the moment.
276 *
277 * By default, the global setting is used.
278 */
279template <typename Type, bool ranged = false>
280class SwitchableSetting : virtual public Setting<Type, ranged> {
281public:
282 /**
283 * Sets a default value, label, and setting value.
284 *
285 * @param linkage Setting registry
286 * @param default_val Initial value of the setting, and default value of the setting
287 * @param name Label for the setting
288 * @param category_ Category of the setting AKA INI group
289 */
290 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
291 Category category, bool save = true, bool runtime_modifiable = false)
292 requires(!ranged)
293 : Setting<Type, false>{linkage, default_val, name, category, save, runtime_modifiable} {
294 linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
295 }
296 virtual ~SwitchableSetting() = default;
297
298 /**
299 * Sets a default value, minimum value, maximum value, and label.
300 *
301 * @param linkage Setting registry
302 * @param default_val Initial value of the setting, and default value of the setting
303 * @param min_val Sets the minimum allowed value of the setting
304 * @param max_val Sets the maximum allowed value of the setting
305 * @param name Label for the setting
306 * @param category_ Category of the setting AKA INI group
307 */
308 explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
309 const Type& max_val, const std::string& name, Category category,
310 bool save = true, bool runtime_modifiable = false)
311 requires(ranged)
312 : Setting<Type, true>{linkage, default_val, min_val, max_val,
313 name, category, save, runtime_modifiable} {
314 linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
315 }
316
317 /**
318 * Tells this setting to represent either the global or custom setting when other member
319 * functions are used.
320 *
321 * @param to_global Whether to use the global or custom setting.
322 */
323 void SetGlobal(bool to_global) override {
324 use_global = to_global;
325 }
326
327 /**
328 * Returns whether this setting is using the global setting or not.
329 *
330 * @returns The global state
331 */
332 [[nodiscard]] bool UsingGlobal() const override {
333 return use_global;
334 }
335
336 /**
337 * Returns either the global or custom setting depending on the values of this setting's global
338 * state or if the global value was specifically requested.
339 *
340 * @param need_global Request global value regardless of setting's state; defaults to false
341 *
342 * @returns The required value of the setting
343 */
344 [[nodiscard]] virtual const Type& GetValue() const override {
345 if (use_global) {
346 return this->value;
347 }
348 return custom;
349 }
350 [[nodiscard]] virtual const Type& GetValue(bool need_global) const {
351 if (use_global || need_global) {
352 return this->value;
353 }
354 return custom;
355 }
356
357 /**
358 * Sets the current setting value depending on the global state.
359 *
360 * @param val The new value
361 */
362 void SetValue(const Type& val) override {
363 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
364 if (use_global) {
365 std::swap(this->value, temp);
366 } else {
367 std::swap(custom, temp);
368 }
369 }
370
371 [[nodiscard]] virtual constexpr bool Switchable() const override {
372 return true;
373 }
374
375 [[nodiscard]] virtual std::string ToStringGlobal() const override {
376 return this->ToString(this->value);
377 }
378
379 /**
380 * Assigns the current setting value depending on the global state.
381 *
382 * @param val The new value
383 *
384 * @returns A reference to the current setting value
385 */
386 const Type& operator=(const Type& val) override {
387 Type temp{ranged ? std::clamp(val, this->minimum, this->maximum) : val};
388 if (use_global) {
389 std::swap(this->value, temp);
390 return this->value;
391 }
392 std::swap(custom, temp);
393 return custom;
394 }
395
396 /**
397 * Returns the current setting value depending on the global state.
398 *
399 * @returns A reference to the current setting value
400 */
401 virtual explicit operator const Type&() const override {
402 if (use_global) {
403 return this->value;
404 }
405 return custom;
406 }
407
408protected:
409 bool use_global{true}; ///< The setting's global state
410 Type custom{}; ///< The custom value of the setting
411};
412
413} // namespace Settings
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 051756452..ba1847976 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -102,9 +102,9 @@ const std::map<Settings::RendererBackend, QString> Config::renderer_backend_text
102}; 102};
103 103
104const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_map = { 104const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_map = {
105 {Settings::ShaderBackend::GLSL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))}, 105 {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))},
106 {Settings::ShaderBackend::GLASM, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))}, 106 {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))},
107 {Settings::ShaderBackend::SPIRV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))}, 107 {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))},
108}; 108};
109 109
110// This shouldn't have anything except static initializers (no functions). So 110// This shouldn't have anything except static initializers (no functions). So
diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp
index efb3b329c..6142c3cb9 100644
--- a/src/yuzu/configuration/shared_widget.cpp
+++ b/src/yuzu/configuration/shared_widget.cpp
@@ -21,7 +21,10 @@
21#include <QStyle> 21#include <QStyle>
22#include <QValidator> 22#include <QValidator>
23#include <QWidget> 23#include <QWidget>
24#include <fmt/core.h>
25#include "common/assert.h"
24#include "common/common_types.h" 26#include "common/common_types.h"
27#include "common/logging/log.h"
25#include "common/settings.h" 28#include "common/settings.h"
26#include "yuzu/configuration/configuration_shared.h" 29#include "yuzu/configuration/configuration_shared.h"
27#include "yuzu/configuration/shared_translation.h" 30#include "yuzu/configuration/shared_translation.h"
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp
index 2c1b547fb..2a02a27bc 100644
--- a/src/yuzu/uisettings.cpp
+++ b/src/yuzu/uisettings.cpp
@@ -3,6 +3,16 @@
3 3
4#include "yuzu/uisettings.h" 4#include "yuzu/uisettings.h"
5 5
6namespace Settings {
7template class Setting<bool>;
8template class Setting<std::string>;
9template class Setting<u16, true>;
10template class Setting<u32>;
11template class Setting<u8, true>;
12template class Setting<u8>;
13template class Setting<unsigned long long>;
14} // namespace Settings
15
6namespace UISettings { 16namespace UISettings {
7 17
8const Themes themes{{ 18const Themes themes{{
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index a734513ea..2152b0b3b 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -17,6 +17,16 @@
17using Settings::Category; 17using Settings::Category;
18using Settings::Setting; 18using Settings::Setting;
19 19
20namespace Settings {
21extern template class Setting<bool>;
22extern template class Setting<std::string>;
23extern template class Setting<u16, true>;
24extern template class Setting<u32>;
25extern template class Setting<u8, true>;
26extern template class Setting<u8>;
27extern template class Setting<unsigned long long>;
28} // namespace Settings
29
20namespace UISettings { 30namespace UISettings {
21 31
22bool IsDarkTheme(); 32bool IsDarkTheme();