summaryrefslogtreecommitdiff
path: root/src/common/settings.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/settings.h')
-rw-r--r--src/common/settings.h513
1 files changed, 42 insertions, 471 deletions
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.