| 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& ) {} |
| 26 |
virtual void loadStart() {} |
| 27 |
virtual void loadLine(std::string_view , zstring_view ) {} |
| 28 |
virtual void loadEnd() {} |
| 29 |
|
| 30 |
virtual void showMenu(MSXMotherBoard* ) {} |
| 31 |
virtual void paint(MSXMotherBoard* ) {} |
| 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 |
|
| 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))); |
| 133 |
} |
| 134 |
void load(C& c, zstring_view value) const { |
| 135 |
this->get(c) = strtof(value.c_str(), nullptr); |
| 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)); |
| 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)); |
| 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 |
} |
| 231 |
|
| 232 |
#endif |