46#include <unordered_set>
67 using Value = std::variant<bool,
96 std::function<
void(
bool)> on_change = {}) {
99 p.key = std::move(key);
100 p.label = std::move(
label);
103 p.on_change = [cb = std::move(on_change)](
const Value&
v) {
104 if (
auto*
b = std::get_if<bool>(&
v)) cb(*
b);
107 register_property(std::move(
p));
111 std::vector<std::string> options,
int initial_index,
112 std::function<
void(
int)> on_change = {}) {
115 p.key = std::move(key);
116 p.label = std::move(
label);
117 p.options = std::move(options);
120 if (
p.options.empty()) {
123 if (initial_index < 0) initial_index = 0;
124 if (initial_index >=
static_cast<int>(
p.options.size())) {
125 initial_index =
static_cast<int>(
p.options.size()) - 1;
127 p.value = initial_index;
130 p.on_change = [cb = std::move(on_change)](
const Value&
v) {
131 if (
auto*
i = std::get_if<int>(&
v)) cb(*
i);
134 register_property(std::move(
p));
138 float initial, std::function<
void(
float)> on_change = {}) {
141 p.key = std::move(key);
142 p.label = std::move(
label);
145 p.value = clamp(initial, min, max);
147 p.on_change = [cb = std::move(on_change)](
const Value&
v) {
148 if (
auto*
f = std::get_if<float>(&
v)) cb(*
f);
151 register_property(std::move(
p));
158 p.key = std::move(key);
159 p.label = std::move(
label);
160 p.value = std::monostate{};
162 register_property(std::move(
p));
166 std::vector<std::string> options,
167 std::vector<int> initial_selection,
168 std::function<
void(
const std::vector<int>&)> on_change = {}) {
171 p.key = std::move(key);
172 p.label = std::move(
label);
173 p.options = std::move(options);
174 normalize_indices(initial_selection,
p.options.size());
175 p.value = std::move(initial_selection);
177 p.on_change = [cb = std::move(on_change)](
const Value&
v) {
178 if (
auto* xs = std::get_if<std::vector<int>>(&
v)) cb(*xs);
181 register_property(std::move(
p));
185 std::function<
void(
const std::string&)> on_change = {}) {
188 p.key = std::move(key);
189 p.label = std::move(
label);
190 p.value = std::move(initial);
192 p.on_change = [cb = std::move(on_change)](
const Value&
v) {
193 if (
auto*
s = std::get_if<std::string>(&
v)) cb(*
s);
196 register_property(std::move(
p));
201 std::size_t
size()
const {
return properties_.size(); }
202 bool empty()
const {
return properties_.empty(); }
204 const std::vector<Property>&
properties()
const {
return properties_; }
207 for (
const auto&
p : properties_) {
208 if (
p.key == key)
return &
p;
213 std::optional<bool>
get_bool(std::string_view key)
const {
214 if (
const auto*
p =
find(key))
215 if (
const auto*
b = std::get_if<bool>(&
p->value))
return *
b;
219 if (
const auto*
p =
find(key))
220 if (
const auto*
i = std::get_if<int>(&
p->value))
return *
i;
223 std::optional<float>
get_slider(std::string_view key)
const {
224 if (
const auto*
p =
find(key))
225 if (
const auto*
f = std::get_if<float>(&
p->value))
return *
f;
229 if (
const auto*
p =
find(key))
230 if (
const auto* xs = std::get_if<std::vector<int>>(&
p->value))
return *xs;
233 std::optional<std::string>
get_text(std::string_view key)
const {
234 if (
const auto*
p =
find(key))
235 if (
const auto*
s = std::get_if<std::string>(&
p->value))
return *
s;
244 auto*
p = find_mut(key);
251 auto*
p = find_mut(key);
253 if (
p->options.empty()) {
256 if (index < 0) index = 0;
257 if (index >=
static_cast<int>(
p->options.size())) {
258 index =
static_cast<int>(
p->options.size()) - 1;
266 auto*
p = find_mut(key);
268 p->value = clamp(
v,
p->min,
p->max);
273 auto*
p = find_mut(key);
275 normalize_indices(selection,
p->options.size());
276 p->value = std::move(selection);
281 auto*
p = find_mut(key);
283 p->value = std::move(
v);
291 auto*
p = find_mut(key);
293 if (
p->on_click)
p->on_click();
301 if (!cur)
return false;
313 if (!cur)
return false;
314 std::vector<int> next = *cur;
317 if (std::find(next.begin(), next.end(), index) == next.end()) {
318 next.push_back(index);
321 next.erase(std::remove(next.begin(), next.end(), index), next.end());
337 for (
auto&
p : properties_) {
344 void register_property(Property
p) {
348 for (
auto& existing : properties_) {
349 if (existing.key ==
p.key) {
350 existing = std::move(
p);
351 if (props_) load_from_props(existing);
355 properties_.push_back(std::move(
p));
356 if (props_) load_from_props(properties_.back());
359 Property* find_mut(std::string_view key) {
360 for (
auto&
p : properties_) {
361 if (
p.key == key)
return &
p;
375 if (
auto*
b = std::get_if<bool>(&
p.value))
376 props_->set_bool(
p.key, *
b);
379 if (
auto*
i = std::get_if<int>(&
p.value))
380 props_->set_int(
p.key, *
i);
383 if (
auto*
f = std::get_if<float>(&
p.value))
384 props_->set_double(
p.key,
static_cast<double>(*
f));
387 if (
auto* xs = std::get_if<std::vector<int>>(&
p.value))
388 props_->set_string(
p.key, encode_indices(*xs));
391 if (
auto*
s = std::get_if<std::string>(&
p.value))
392 props_->set_string(
p.key, *
s);
403 if (
auto v = props_->get_bool(
p.key))
p.value = *
v;
406 if (
auto v = props_->get_int(
p.key)) {
407 int i =
static_cast<int>(*v);
408 if (!
p.options.empty()) {
410 if (
i >=
static_cast<int>(
p.options.size())) {
411 i =
static_cast<int>(
p.options.size()) - 1;
420 if (
auto v = props_->get_double(
p.key)) {
421 p.value = clamp(
static_cast<float>(*
v),
p.min,
p.max);
425 if (
auto v = props_->get_string(
p.key)) {
426 auto xs = decode_indices(*
v);
427 normalize_indices(xs,
p.options.size());
428 p.value = std::move(xs);
432 if (
auto v = props_->get_string(
p.key))
p.value = *
v;
439 static float clamp(
float v,
float lo,
float hi) {
440 if (hi < lo)
return v;
441 if (
v < lo)
return lo;
442 if (
v > hi)
return hi;
445 static void normalize_indices(std::vector<int>& xs, std::size_t option_count) {
446 std::unordered_set<int> seen;
447 std::vector<int> out;
448 out.reserve(xs.size());
451 && (
i < 0 || i >=
static_cast<int>(option_count)))
continue;
452 if (seen.insert(
i).second) out.push_back(
i);
454 std::sort(out.begin(), out.end());
457 static std::string encode_indices(
const std::vector<int>& xs) {
459 for (std::size_t
i = 0;
i < xs.size(); ++
i) {
460 if (
i) out.push_back(
',');
461 out += std::to_string(xs[
i]);
465 static std::vector<int> decode_indices(std::string_view
s) {
466 std::vector<int> out;
468 while (
i <
s.size()) {
469 std::size_t
j =
s.find(
',',
i);
470 if (
j == std::string_view::npos)
j =
s.size();
471 auto tok =
s.substr(
i,
j -
i);
473 while (!tok.empty() && (tok.front() ==
' ' || tok.front() ==
'\t'))
474 tok.remove_prefix(1);
475 while (!tok.empty() && (tok.back() ==
' ' || tok.back() ==
'\t'))
476 tok.remove_suffix(1);
479 out.push_back(std::stoi(std::string(tok)));
490 std::vector<Property> properties_;
491 pulp::state::PropertiesFile* props_ =
nullptr;
JSON-backed persistent settings file.
Definition properties_file.hpp:16
bool simulate_choose(std::string_view key, int index)
Definition property_panel.hpp:304
bool simulate_set_text(std::string_view key, std::string v)
Definition property_panel.hpp:325
std::optional< bool > get_bool(std::string_view key) const
Definition property_panel.hpp:213
bool click(std::string_view key)
Click a Button property.
Definition property_panel.hpp:290
void add_multi_choice(std::string key, std::string label, std::vector< std::string > options, std::vector< int > initial_selection, std::function< void(const std::vector< int > &)> on_change={})
Definition property_panel.hpp:165
const Property * find(std::string_view key) const
Definition property_panel.hpp:206
std::size_t size() const
Definition property_panel.hpp:201
bool set_text(std::string_view key, std::string v)
Definition property_panel.hpp:280
void add_slider(std::string key, std::string label, float min, float max, float initial, std::function< void(float)> on_change={})
Definition property_panel.hpp:137
bool set_bool(std::string_view key, bool v)
Set a Boolean property.
Definition property_panel.hpp:243
void add_choice(std::string key, std::string label, std::vector< std::string > options, int initial_index, std::function< void(int)> on_change={})
Definition property_panel.hpp:110
const std::vector< Property > & properties() const
Definition property_panel.hpp:204
void add_boolean(std::string key, std::string label, bool initial, std::function< void(bool)> on_change={})
Definition property_panel.hpp:95
bool empty() const
Definition property_panel.hpp:202
void add_text(std::string key, std::string label, std::string initial, std::function< void(const std::string &)> on_change={})
Definition property_panel.hpp:184
std::optional< float > get_slider(std::string_view key) const
Definition property_panel.hpp:223
void add_button(std::string key, std::string label, std::function< void()> on_click)
Definition property_panel.hpp:154
bool set_slider(std::string_view key, float v)
Definition property_panel.hpp:265
std::variant< bool, int, float, std::vector< int >, std::string, std::monostate > Value
Definition property_panel.hpp:67
bool set_multi_choice(std::string_view key, std::vector< int > selection)
Definition property_panel.hpp:272
std::optional< int > get_choice(std::string_view key) const
Definition property_panel.hpp:218
bool simulate_toggle(std::string_view key)
Definition property_panel.hpp:299
bool set_choice(std::string_view key, int index)
Definition property_panel.hpp:250
bool has_persistence() const
Definition property_panel.hpp:341
void bind_persistence(pulp::state::PropertiesFile *props)
Bind the panel to a PropertiesFile.
Definition property_panel.hpp:334
bool simulate_click(std::string_view key)
Definition property_panel.hpp:310
std::optional< std::vector< int > > get_multi_choice(std::string_view key) const
Definition property_panel.hpp:228
bool simulate_multi_check(std::string_view key, int index, bool on)
Definition property_panel.hpp:311
Kind
Definition property_panel.hpp:58
@ Slider
float in [min, max]
Definition property_panel.hpp:61
@ Choice
single int index into options
Definition property_panel.hpp:60
@ Button
action only (no persisted state)
Definition property_panel.hpp:62
@ Text
std::string value
Definition property_panel.hpp:64
@ BooleanToggle
bool — round-trips as 0/1
Definition property_panel.hpp:59
@ MultiChoice
ordered set of int indices into options
Definition property_panel.hpp:63
std::optional< std::string > get_text(std::string_view key) const
Definition property_panel.hpp:233
bool simulate_slide(std::string_view key, float v)
Definition property_panel.hpp:307
std::function< void()> on_click
Generic click callback (fires on mouse-down, if set).
Definition view.hpp:1476
@ label
Definition view.hpp:989
Hover-cursor tracking for platform window hosts.
Definition fwd.hpp:27
@ s
Definition input_events.hpp:41
@ j
Definition input_events.hpp:40
@ p
Definition input_events.hpp:40
@ i
Definition input_events.hpp:40
@ f
Definition input_events.hpp:39
@ b
Definition input_events.hpp:39
@ v
Definition input_events.hpp:41
@ on
Definition accessibility.hpp:132
Definition property_panel.hpp:74
std::string key
Persistence + lookup key.
Definition property_panel.hpp:75
Kind kind
Definition property_panel.hpp:77
Value value
Definition property_panel.hpp:78
std::string label
Display label.
Definition property_panel.hpp:76
float min
Definition property_panel.hpp:80
std::function< void(const Value &)> on_change
Definition property_panel.hpp:86
float max
Definition property_panel.hpp:81
std::vector< std::string > options
Definition property_panel.hpp:83
std::function< void()> on_click
Definition property_panel.hpp:88