OXYGENHUB
◆ main openmsx / src / settings / Setting.hh
5.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef SETTING_HH
2
#define SETTING_HH
3
4
#include "Subject.hh"
5
#include "TclObject.hh"
6
#include "static_string_view.hh"
7
#include "strCat.hh"
8
9
#include <cassert>
10
#include <cstdint>
11
#include <functional>
12
#include <optional>
13
#include <string_view>
14
#include <vector>
15
16
namespace openmsx {
17
18
class CommandController;
19
class GlobalCommandController;
20
class Interpreter;
21
22
class BaseSetting
23
{
24
protected:
25
	explicit BaseSetting(std::string_view name);
26
	explicit BaseSetting(TclObject name);
27
	~BaseSetting() = default;
28
29
public:
30
	/** Get the name of this setting.
31
	  * For global settings 'fullName' and 'baseName' are the same. For
32
	  * machine specific settings 'fullName' is the fully qualified name,
33
	  * and 'baseName' is the name without machine-prefix. For example:
34
	  *   fullName = "::machine1::PSG_volume"
35
	  *   baseName = "PSG_volume"
36
	  */
37
	[[nodiscard]] const TclObject& getFullNameObj() const { return fullName; }
38
	[[nodiscard]] const TclObject& getBaseNameObj() const { return baseName; }
39
	[[nodiscard]] std::string_view getFullName()    const { return fullName.getString(); }
40
	[[nodiscard]] std::string_view getBaseName()    const { return baseName.getString(); }
41
42
	/** Set a machine specific prefix.
43
	 */
44
	void setPrefix(std::string_view prefix) {
45
		assert(prefix.starts_with("::"));
46
		fullName = tmpStrCat(prefix, getBaseName());
47
	}
48
49
	/** For SettingInfo
50
	  */
51
	void info(TclObject& result) const;
52
53
	/// pure virtual methods ///
54
55
	/** Get a description of this setting that can be presented to the user.
56
	  */
57
	[[nodiscard]] virtual std::string_view getDescription() const = 0;
58
59
	/** Returns a string describing the setting type (integer, string, ..)
60
	  * Could be used in a GUI to pick an appropriate setting widget.
61
	  */
62
	[[nodiscard]] virtual std::string_view getTypeString() const = 0;
63
64
	/** Helper method for info().
65
	 */
66
	virtual void additionalInfo(TclObject& result) const = 0;
67
68
	/** Complete a partly typed value.
69
	  * Default implementation does not complete anything,
70
	  * subclasses can override this to complete according to their
71
	  * specific value type.
72
	  */
73
	virtual void tabCompletion(std::vector<std::string>& tokens) const = 0;
74
75
	/** Get current value as a TclObject.
76
	 */
77
	[[nodiscard]] virtual const TclObject& getValue() const = 0;
78
79
	/** Like getValue(), but in case of error returns an empty optional
80
	  * instead of throwing an exception.
81
	  */
82
	[[nodiscard]] virtual std::optional<TclObject> getOptionalValue() const = 0;
83
84
	/** Get the default value of this setting.
85
	  * This is the initial value of the setting. Default values don't
86
	  * get saved in 'settings.xml'.
87
	  * This is also the value used for a Tcl 'unset' command.
88
	  */
89
	[[nodiscard]] virtual TclObject getDefaultValue() const = 0;
90
91
	/** Change the value of this setting to the given value.
92
	  * This method will trigger Tcl traces.
93
	  * This value still passes via the 'checker-callback' (see below),
94
	  * so the value may be adjusted. Or in case of an invalid value
95
	  * this method may throw.
96
	  */
97
	virtual void setValue(const TclObject& value) = 0;
98
99
	/** Similar to setValue(), but doesn't trigger Tcl traces.
100
	  * Like setValue(), the given value may be adjusted or rejected.
101
	  * Should only be used by the Interpreter class.
102
	  */
103
	virtual void setValueDirect(const TclObject& value) = 0;
104
105
	/** Does this setting need to be loaded or saved (settings.xml).
106
	  */
107
	[[nodiscard]] virtual bool needLoadSave() const = 0;
108
109
	/** Does this setting need to be transfered on reverse.
110
	  */
111
	[[nodiscard]] virtual bool needTransfer() const = 0;
112
113
private:
114
	      TclObject fullName;
115
	const TclObject baseName;
116
};
117
118
119
class Setting : public BaseSetting, public Subject<Setting>
120
{
121
public:
122
	enum class Save : uint8_t {
123
		YES,                  //    save,    transfer
124
		NO,                   // no-save,    transfer
125
		NO_AND_DONT_TRANSFER, // no-save, no-transfer
126
	};
127
128
	Setting(const Setting&) = delete;
129
	Setting(Setting&&) = delete;
130
	Setting& operator=(const Setting&) = delete;
131
	Setting& operator=(Setting&&) = delete;
132
	virtual ~Setting();
133
134
	/** Gets the current value of this setting as a TclObject.
135
	  */
136
	[[nodiscard]] const TclObject& getValue() const final { return value; }
137
	[[nodiscard]] std::optional<TclObject> getOptionalValue() const final { return value; }
138
139
	/** Set value-check-callback.
140
	 * The callback is called on each change of this settings value.
141
	 * The callback has the possibility to
142
	 *  - change the value (modify the parameter)
143
	 *  - disallow the change (throw an exception)
144
	 * The callback is only executed on each value change, even if the
145
	 * new value is the same as the current value. However the callback
146
	 * is not immediately executed once it's set (via this method).
147
	 */
148
	void setChecker(std::function<void(TclObject&)> checkFunc_) {
149
		checkFunc = std::move(checkFunc_);
150
	}
151
152
	// BaseSetting
153
	void setValue(const TclObject& newValue) final;
154
	[[nodiscard]] std::string_view getDescription() const final;
155
	[[nodiscard]] TclObject getDefaultValue() const final { return defaultValue; }
156
	void setValueDirect(const TclObject& newValue) final;
157
	void tabCompletion(std::vector<std::string>& tokens) const override;
158
	[[nodiscard]] bool needLoadSave() const final;
159
	void additionalInfo(TclObject& result) const override;
160
	[[nodiscard]] bool needTransfer() const final;
161
162
	// convenience functions
163
	[[nodiscard]] CommandController& getCommandController() const { return commandController; }
164
	[[nodiscard]] Interpreter& getInterpreter() const;
165
166
protected:
167
	Setting(CommandController& commandController,
168
	        std::string_view name, static_string_view description,
169
	        const TclObject& initialValue, Save save = Save::YES);
170
	void init();
171
	void notifyPropertyChange() const;
172
173
private:
174
	[[nodiscard]] GlobalCommandController& getGlobalCommandController() const;
175
	void notify() const;
176
177
private:
178
	CommandController& commandController;
179
	const static_string_view description;
180
	std::function<void(TclObject&)> checkFunc;
181
	TclObject value; // TODO can we share the underlying Tcl var storage?
182
	const TclObject defaultValue;
183
	const Save save;
184
};
185
186
} // namespace openmsx
187
188
#endif