OXYGENHUB
◆ main openmsx / src / imgui / ImGuiPartInterface.hh
6.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef IMGUI_PARTINTERFACE_HH
2
#define IMGUI_PARTINTERFACE_HH
3
4
#include "ImGuiCpp.hh"
5
6
#include "StringOp.hh"
7
#include "escape_newline.hh"
8
#include "stl.hh"
9
#include "zstring_view.hh"
10
11
#include <initializer_list>
12
#include <string>
13
#include <string_view>
14
15
#include <imgui.h>
16
17
namespace openmsx {
18
19
class MSXMotherBoard;
20
21
class ImGuiPartInterface
22
{
23
public:
24
	[[nodiscard]] virtual zstring_view iniName() const { return ""; }
25
	virtual void save(ImGuiTextBuffer& /*buf*/) {}
26
	virtual void loadStart() {}
27
	virtual void loadLine(std::string_view /*name*/, zstring_view /*value*/) {}
28
	virtual void loadEnd() {}
29
30
	virtual void showMenu(MSXMotherBoard* /*motherBoard*/) {}
31
	virtual void paint(MSXMotherBoard* /*motherBoard*/) {}
32
};
33
34
////
35
36
template<typename C, typename T> struct PersistentElementBase {
37
	constexpr PersistentElementBase(zstring_view name_, T C::*p_)
38
	        : name(name_), p(p_) {}
39
40
	zstring_view name;
41
	T C::*p;
42
43
	T& get(C& c) const { return c.*p; }
44
};
45
46
// 'PersistentElement' base-case, will be partially specialized for concrete 'T'.
47
template<typename C, typename T>
48
struct PersistentElement;
49
template<typename C, typename T>
50
PersistentElement(zstring_view, T C::*) -> PersistentElement<C, T>;
51
52
template<typename C>
53
struct PersistentElement<C, int> : PersistentElementBase<C, int> {
54
	using PersistentElementBase<C, int>::PersistentElementBase;
55
	void save(ImGuiTextBuffer& buf, C& c) const {
56
		buf.appendf("%s=%d\n", this->name.c_str(), this->get(c));
57
	}
58
	void load(C& c, zstring_view value) const {
59
		if (auto r = StringOp::stringTo<int>(value)) {
60
			this->get(c) = *r;
61
		}
62
	}
63
};
64
65
template<typename C>
66
struct PersistentElementMax : PersistentElement<C, int> {
67
	int max;
68
	constexpr PersistentElementMax(zstring_view name_, int C::*p_, int max_)
69
		: PersistentElement<C, int>(name_, p_), max(max_) {}
70
71
	void load(C& c, std::string_view value) const {
72
		if (auto r = StringOp::stringTo<int>(value)) {
73
			if (0 <= *r && *r < max) this->get(c) = *r;
74
		}
75
	}
76
};
77
78
template<typename C>
79
struct PersistentElementMinMax : PersistentElement<C, int> {
80
	int min, max;
81
	constexpr PersistentElementMinMax(zstring_view name_, int C::*p_, int min_, int max_)
82
		: PersistentElement<C, int>(name_, p_), min(min_), max(max_) {}
83
84
	void load(C& c, std::string_view value) const {
85
		if (auto r = StringOp::stringTo<int>(value)) {
86
			if (min <= *r && *r < max) this->get(c) = *r;
87
		}
88
	}
89
};
90
91
template<typename C>
92
struct PersistentElementEnum : PersistentElement<C, int> {
93
	std::initializer_list<int> valid;
94
	constexpr PersistentElementEnum(zstring_view name_, int C::*p_, std::initializer_list<int> valid_)
95
		: PersistentElement<C, int>(name_, p_), valid(valid_) {}
96
97
	void load(C& c, std::string_view value) const {
98
		if (auto r = StringOp::stringTo<int>(value)) {
99
			if (contains(valid, *r)) this->get(c) = *r;
100
		}
101
	}
102
};
103
104
template<typename C>
105
struct PersistentElement<C, unsigned> : PersistentElementBase<C, unsigned> {
106
	using PersistentElementBase<C, unsigned>::PersistentElementBase;
107
	void save(ImGuiTextBuffer& buf, C& c) const {
108
		buf.appendf("%s=%u\n", this->name.c_str(), this->get(c));
109
	}
110
	void load(C& c, zstring_view value) const {
111
		if (auto r = StringOp::stringTo<unsigned>(value)) {
112
			this->get(c) = *r;
113
		}
114
	}
115
};
116
117
template<typename C>
118
struct PersistentElement<C, bool> : PersistentElementBase<C, bool> {
119
	using PersistentElementBase<C, bool>::PersistentElementBase;
120
	void save(ImGuiTextBuffer& buf, C& c) const {
121
		buf.appendf("%s=%d\n", this->name.c_str(), this->get(c));
122
	}
123
	void load(C& c, zstring_view value) const {
124
		this->get(c) = StringOp::stringToBool(value);
125
	}
126
};
127
128
template<typename C>
129
struct PersistentElement<C, float> : PersistentElementBase<C, float> {
130
	using PersistentElementBase<C, float>::PersistentElementBase;
131
	void save(ImGuiTextBuffer& buf, C& c) const {
132
		buf.appendf("%s=%f\n", this->name.c_str(), double(this->get(c))); // cast to silence warning
133
	}
134
	void load(C& c, zstring_view value) const {
135
		this->get(c) = strtof(value.c_str(), nullptr); // TODO error handling
136
	}
137
};
138
139
template<typename C>
140
struct PersistentElement<C, std::string> : PersistentElementBase<C, std::string> {
141
	using PersistentElementBase<C, std::string>::PersistentElementBase;
142
	void save(ImGuiTextBuffer& buf, C& c) const {
143
		buf.appendf("%s=%s\n", this->name.c_str(), escape_newline::encode(this->get(c)).c_str());
144
	}
145
	void load(C& c, zstring_view value) const {
146
		this->get(c) = escape_newline::decode(value);
147
	}
148
};
149
150
template<typename C>
151
struct PersistentElement<C, gl::ivec2> : PersistentElementBase<C, gl::ivec2> {
152
	using PersistentElementBase<C, gl::ivec2>::PersistentElementBase;
153
	void save(ImGuiTextBuffer& buf, C& c) const {
154
		const auto& v = this->get(c);
155
		buf.appendf("%s=[ %d %d ]\n", this->name.c_str(), v.x, v.y);
156
	}
157
	void load(C& c, zstring_view value) const {
158
		gl::ivec2 t;
159
		if (sscanf(value.c_str(), "[ %d %d ]", &t.x, &t.y) == 2) {
160
			this->get(c) = t;
161
		}
162
	}
163
};
164
165
template<typename C>
166
struct PersistentElement<C, gl::vec2> : PersistentElementBase<C, gl::vec2> {
167
	using PersistentElementBase<C, gl::vec2>::PersistentElementBase;
168
	void save(ImGuiTextBuffer& buf, C& c) const {
169
		const auto& v = this->get(c);
170
		buf.appendf("%s=[ %f %f ]\n", this->name.c_str(),
171
			double(v.x), double(v.y)); // note: cast only needed to silence warnings
172
	}
173
	void load(C& c, zstring_view value) const {
174
		gl::vec2 t;
175
		if (sscanf(value.c_str(), "[ %f %f ]", &t.x, &t.y) == 2) {
176
			this->get(c) = t;
177
		}
178
	}
179
};
180
181
template<typename C>
182
struct PersistentElement<C, gl::vec4> : PersistentElementBase<C, gl::vec4> {
183
	using PersistentElementBase<C, gl::vec4>::PersistentElementBase;
184
	void save(ImGuiTextBuffer& buf, C& c) const {
185
		const auto& v = this->get(c);
186
		buf.appendf("%s=[ %f %f %f %f ]\n", this->name.c_str(),
187
			double(v.x), double(v.y), double(v.z), double(v.w)); // note: cast only needed to silence warnings
188
	}
189
	void load(C& c, zstring_view value) const {
190
		gl::vec4 t;
191
		if (sscanf(value.c_str(), "[ %f %f %f %f ]", &t.x, &t.y, &t.z, &t.w) == 4) {
192
			this->get(c) = t;
193
		}
194
	}
195
};
196
197
template<typename C>
198
struct PersistentElement<C, im::WindowStatus> : PersistentElementBase<C, im::WindowStatus> {
199
	using PersistentElementBase<C, im::WindowStatus>::PersistentElementBase;
200
	void save(ImGuiTextBuffer& buf, C& c) const {
201
		buf.appendf("%s=%d\n", this->name.c_str(), this->get(c).open);
202
	}
203
	void load(C& c, zstring_view value) const {
204
		this->get(c).open = StringOp::stringToBool(value);
205
	}
206
};
207
208
209
template<typename C, typename... Elements>
210
void savePersistent(ImGuiTextBuffer& buf, C& c, const std::tuple<Elements...>& tup)
211
{
212
	std::apply([&](auto& ...elem){(..., elem.save(buf, c));}, tup);
213
}
214
215
template<typename C, typename Elem>
216
bool checkLoad(std::string_view name, zstring_view value,
217
               C& c, Elem& elem)
218
{
219
	if (name != elem.name) return false;
220
	elem.load(c, value);
221
	return true;
222
}
223
template<typename C, typename... Elements>
224
bool loadOnePersistent(std::string_view name, zstring_view value,
225
              C& c, const std::tuple<Elements...>& tup)
226
{
227
	return std::apply([&](auto& ...elem){ return (... || checkLoad(name, value, c, elem));}, tup);
228
}
229
230
} // namespace openmsx
231
232
#endif