SatDump 2.0.0-alpha-76a915210
Loading...
Searching...
No Matches
options_displayer.h
1#pragma once
2
3#include "common/widgets/stepped_slider.h"
4#include "core/exception.h"
5#include "core/style.h"
6#include "imgui/imgui.h"
7#include "imgui/imgui_stdlib.h"
8#include "nlohmann/json.hpp"
9#include <cstddef>
10#include <cstdint>
11#include <mutex>
12#include <string>
13
14#include "common/widgets/double_list.h"
15#include "common/widgets/frequency_input.h"
16
17#include "logger.h"
18#include "nlohmann/json_utils.h"
19
20namespace satdump
21{
22 namespace ndsp // TODOREWORK rename!!!!! And move to somewhere more generic!!!! And document!!!
23 {
25 {
26 private:
27 struct OptHolder
28 {
29 // ID
30 std::string id;
31 std::string name;
32 bool disable = false;
33
34 // Type
35 bool is_bool = false;
36 bool is_string = false;
37 bool is_uint = false;
38 bool is_int = false;
39 bool is_float = false;
40 bool is_freq = false;
41 bool is_samplerate = false;
42
43 // bool is_sub = false;
44
45 bool is_list = false;
46 bool is_range = false;
47 bool is_range_noslider = false;
48 bool is_range_list = false;
49
50 // Value config. TODOREWORK, handle lists as uint64_t too?
51 std::vector<double> list;
52 std::vector<std::string> list_string;
53 std::array<double, 3> range;
54
55 // Holding values
56 bool _bool = false;
57 std::string _string = "";
58 uint64_t _uint = 0;
59 int64_t _int = 0;
60 double _float = 0;
61 std::shared_ptr<widgets::DoubleList> _samplerate;
62 };
63
64 std::mutex opts_mtx;
65 std::vector<OptHolder> opts;
66
67 inline void get_val(OptHolder &v, nlohmann::json &j)
68 {
69 if (v.is_bool)
70 j = v._bool;
71 else if (v.is_string)
72 j = v._string;
73 else if (v.is_uint || v.is_freq)
74 j = v._uint;
75 else if (v.is_int)
76 j = v._int;
77 else if (v.is_float)
78 j = v._float;
79 else if (v.is_samplerate)
80 j = v._samplerate->get_value();
81 else
82 throw satdump_exception("Invalid options or JSON value! (GET " + v.id + ")");
83 }
84
85 public:
86 void add_options(nlohmann::ordered_json options)
87 {
88 opts_mtx.lock();
89 for (auto &v : options.items())
90 {
91 auto &vv = v.value();
92 OptHolder h;
93 h.id = v.key();
94
95 // Validate and parse config
96 if (!vv.contains("type"))
97 throw satdump_exception("Option " + v.key() + " does not have type!");
98
99 // May be hidden!
100 if (vv.contains("hide"))
101 if (vv["hide"].get<bool>())
102 continue;
103
104 if (vv.contains("disable"))
105 h.disable = vv["disable"].get<bool>();
106
107 if (vv.contains("name"))
108 h.name = vv["name"];
109 else
110 h.name = h.id;
111
112 h.is_bool = vv["type"] == "bool";
113 h.is_string = vv["type"] == "string";
114 h.is_uint = vv["type"] == "uint";
115 h.is_int = vv["type"] == "int";
116 h.is_float = vv["type"] == "float";
117 h.is_freq = vv["type"] == "freq";
118 h.is_samplerate = vv["type"] == "samplerate";
119
120 h.is_list = vv.contains("list");
121 if (h.is_list)
122 {
123 if (h.is_string)
124 h.list_string = vv["list"].get<std::vector<std::string>>();
125 else
126 h.list = vv["list"].get<std::vector<double>>();
127 }
128
129 h.is_range = vv.contains("range");
130 if (h.is_range)
131 {
132 h.range = vv["range"].get<std::array<double, 3>>();
133 if (vv.contains("range_noslider"))
134 h.is_range_noslider = vv["range_noslider"];
135 }
136
137 h.is_range_list = h.is_list && h.is_range;
138
139 if (h.is_samplerate)
140 {
141 h._samplerate = std::make_shared<widgets::DoubleList>(h.name);
142 h._samplerate->set_list(vv["list"], getValueOrDefault(vv["allow_manual"], false));
143 }
144
145 // Defaults
146 if (vv.contains("default"))
147 {
148 if (h.is_bool)
149 h._bool = vv["default"];
150 else if (h.is_string)
151 h._string = vv["default"];
152 else if (h.is_uint)
153 h._uint = vv["default"];
154 else if (h.is_int)
155 h._int = vv["default"];
156 else if (h.is_float)
157 h._float = vv["default"];
158 }
159
160 opts.push_back(h);
161 }
162 opts_mtx.unlock();
163 }
164
165 void clear()
166 {
167 opts_mtx.lock();
168 opts.clear();
169 opts_mtx.unlock();
170 }
171
172 void set_values(nlohmann::json vals)
173 {
174 opts_mtx.lock();
175 for (auto &v : opts)
176 {
177 if (vals.contains(v.id))
178 {
179 auto &j = vals[v.id];
180 if (v.is_bool && j.is_boolean())
181 v._bool = j;
182 else if (v.is_string && j.is_string())
183 v._string = j;
184 else if ((v.is_uint || v.is_freq) && j.is_number())
185 v._uint = j;
186 else if (v.is_int && j.is_number())
187 v._int = j;
188 else if (v.is_float && j.is_number())
189 v._float = j;
190 else if (v.is_samplerate && j.is_number())
191 v._samplerate->set_value(j);
192 else
193 logger->error("Invalid options or JSON value! (SET " + v.id + " => " + j.dump() + ")");
194 }
195 }
196 opts_mtx.unlock();
197 }
198
199 nlohmann::json get_values()
200 {
201 opts_mtx.lock();
202 nlohmann::json vals;
203 for (auto &v : opts)
204 get_val(v, vals[v.id]);
205 opts_mtx.unlock();
206 return vals;
207 }
208
209 nlohmann::json draw()
210 {
211 nlohmann::json vals;
212
213 opts_mtx.lock();
214 for (auto &v : opts)
215 {
216 bool u = false;
217 std::string id = std::string(v.name + "##" + std::to_string((size_t)this));
218 std::string id_n = std::string(v.name);
219
220 if (v.disable)
221 style::beginDisabled();
222
223 if (v.is_bool)
224 {
225 u |= ImGui::Checkbox(id.c_str(), &v._bool);
226 }
227 else if (v.is_list && v.is_string)
228 {
229 if (ImGui::BeginCombo(id.c_str(), v._string.c_str()))
230 {
231 for (auto &i : v.list_string)
232 if (ImGui::Selectable(i.c_str(), i == v._string))
233 u = true, v._string = i;
234 ImGui::EndCombo();
235 }
236 }
237 else if (v.is_string)
238 {
239 ImGui::InputText(id.c_str(), &v._string);
240 u |= ImGui::IsItemDeactivatedAfterEdit();
241 }
242 else if (v.is_range && v.is_int)
243 {
244 // TODOREWORK ALLOW LARGE INT
245 int lv = v._int;
246 u |= widgets::SteppedSliderInt(id_n.c_str(), &lv, v.range[0], v.range[1], v.range[2]);
247 v._int = lv;
248 }
249 else if (v.is_range && v.is_uint)
250 {
251 // TODOREWORK ALLOW LARGE INT
252 int lv = v._uint;
253 if (v.is_range_noslider)
254 {
255 u |= ImGui::InputInt(id_n.c_str(), &lv);
256 if (lv < v.range[0])
257 lv = v.range[0];
258 if (lv > v.range[1])
259 lv = v.range[1];
260 }
261 else
262 u |= widgets::SteppedSliderInt(id_n.c_str(), &lv, v.range[0], v.range[1], v.range[2]);
263 v._uint = lv;
264 }
265 else if (v.is_range && v.is_float)
266 {
267 // TODOREWORK USE DOUBLE INSTEAD
268 float lv = v._float;
269 u |= widgets::SteppedSliderFloat(id_n.c_str(), &lv, v.range[0], v.range[1], v.range[2]);
270 v._float = lv;
271 }
272 else if (v.is_list && v.is_int)
273 {
274 // TODOREWORK USE LARGE INT INSTEAD
275 if (ImGui::BeginCombo(id.c_str(), std::to_string(v._int).c_str()))
276 {
277 for (auto &i : v.list)
278 if (ImGui::Selectable(std::to_string(i).c_str(), i == v._int))
279 u = true, v._int = i;
280 ImGui::EndCombo();
281 }
282 }
283 else if (v.is_list && v.is_uint)
284 {
285 // TODOREWORK USE LARGE INT INSTEAD
286 if (ImGui::BeginCombo(id.c_str(), std::to_string(v._uint).c_str()))
287 {
288 for (auto &i : v.list)
289 if (ImGui::Selectable(std::to_string(i).c_str(), i == v._uint))
290 u = true, v._uint = i;
291 ImGui::EndCombo();
292 }
293 }
294 else if (v.is_list && v.is_float)
295 {
296 // TODOREWORK USE DOUBLE INSTEAD
297 if (ImGui::BeginCombo(id.c_str(), std::to_string(v._float).c_str()))
298 {
299 for (auto &i : v.list)
300 if (ImGui::Selectable(std::to_string(i).c_str(), i == v._float))
301 u = true, v._float = i;
302 ImGui::EndCombo();
303 }
304 }
305 else if (v.is_int)
306 {
307 // TODOREWORK USE LARGE INT INSTEAD
308 int lv = v._int;
309 ImGui::InputInt(id.c_str(), &lv);
310 u |= ImGui::IsItemDeactivatedAfterEdit();
311 v._int = lv;
312 }
313 else if (v.is_uint)
314 {
315 // TODOREWORK USE LARGE INT INSTEAD
316 int lv = v._uint;
317 ImGui::InputInt(id.c_str(), &lv);
318 u |= ImGui::IsItemDeactivatedAfterEdit();
319 v._uint = lv;
320 }
321 else if (v.is_float)
322 {
323 // TODOREWORK USE DOUBLE INSTEAD
324 ImGui::InputDouble(id.c_str(), &v._float);
325 u |= ImGui::IsItemDeactivatedAfterEdit();
326 }
327 else if (v.is_freq)
328 {
329 u |= widgets::FrequencyInput(id.c_str(), &v._uint, 0, false);
330 // TODOREWORK handle ranges
331 }
332 else if (v.is_samplerate)
333 {
334 u |= v._samplerate->render();
335 }
336 else
337 {
338 ImGui::Text("Unimplemented : %s", id.c_str());
339 }
340
341 if (v.is_range_list)
342 if (ImGui::Checkbox(("Manual " + v.name).c_str(), &v.is_range))
343 v.is_list = !v.is_range;
344
345 if (v.disable)
346 style::endDisabled();
347
348 if (u)
349 get_val(v, vals[v.id]);
350 }
351 opts_mtx.unlock();
352 return vals;
353 }
354 };
355 } // namespace ndsp
356} // namespace satdump
Definition options_displayer.h:25