Loading...
Searching...
No Matches
ControlWidgetDomains.hpp
1#pragma once
2#include <Process/Dataflow/Port.hpp>
3
4#include <score/tools/Debug.hpp>
5
6#include <ossia/detail/math.hpp>
7#include <ossia/network/domain/domain.hpp>
8
9#include <QDoubleSpinBox>
10#include <QSpinBox>
11
12#include <type_traits>
13
14namespace WidgetFactory
15{
16
17template <typename T>
18static constexpr auto getMin(auto& slider) noexcept
19{
20 if constexpr(requires { slider.getMin(); })
21 return slider.getMin();
22 else
23 return slider.domain().get().template convert_min<T>();
24}
25
26template <typename T>
27static constexpr auto getMax(auto& slider) noexcept
28{
29 if constexpr(requires { slider.getMax(); })
30 return slider.getMax();
31 else
32 return slider.domain().get().template convert_max<T>();
33}
34
35template <typename T>
36static constexpr auto getInit(auto& slider) noexcept
37{
38 if constexpr(requires { slider.getInit(); })
39 return slider.getInit();
40 else if constexpr(requires { slider.init(); })
41 return ossia::convert<T>(slider.init());
42 else
43 return getMin<T>(slider);
44}
45
47{
48 static constexpr double to01(double min, double range, double val) noexcept
49 {
50 return (val - min) / range;
51 }
52
53 static constexpr double from01(double min, double range, double val) noexcept
54 {
55 return min + val * range;
56 }
57
58 template <typename T>
59 static double to01(const T& slider, double val) noexcept
60 {
61 auto min = getMin<double>(slider);
62 auto max = getMax<double>(slider);
63 if(max - min == 0)
64 max = min + 1;
65 return to01(min, max - min, val);
66 }
67
68 template <typename T>
69 static double from01(const T& slider, double val) noexcept
70 {
71 auto min = getMin<double>(slider);
72 auto max = getMax<double>(slider);
73 if(max - min == 0)
74 max = min + 1;
75 return from01(min, max - min, val);
76 }
77
78 template <typename T>
79 static std::array<double, 2> to01(const T& slider, ossia::vec2f val) noexcept
80 {
81 std::array<double, 2> res;
82 const auto min = getMin<ossia::vec2f>(slider);
83 const auto max = getMax<ossia::vec2f>(slider);
84 res[0] = to01(min[0], double(max[0]) - double(min[0]), val[0]);
85 res[1] = to01(min[1], double(max[1]) - double(min[1]), val[1]);
86 return res;
87 }
88
89 template <typename T>
90 static ossia::vec2f from01(const T& slider, std::array<double, 2> val) noexcept
91 {
92 ossia::vec2f res;
93 const auto min = getMin<ossia::vec2f>(slider);
94 const auto max = getMax<ossia::vec2f>(slider);
95 res[0] = from01(min[0], double(max[0]) - double(min[0]), val[0]);
96 res[1] = from01(min[1], double(max[1]) - double(min[1]), val[1]);
97 return res;
98 }
99
100 template <typename T>
101 static std::array<double, 3> to01(const T& slider, ossia::vec3f val) noexcept
102 {
103 std::array<double, 3> res;
104 const auto min = getMin<ossia::vec3f>(slider);
105 const auto max = getMax<ossia::vec3f>(slider);
106 res[0] = to01(min[0], double(max[0]) - double(min[0]), val[0]);
107 res[1] = to01(min[1], double(max[1]) - double(min[1]), val[1]);
108 res[2] = to01(min[2], double(max[2]) - double(min[2]), val[2]);
109 return res;
110 }
111
112 template <typename T>
113 static ossia::vec3f from01(const T& slider, std::array<double, 3> val) noexcept
114 {
115 ossia::vec3f res;
116 const auto min = getMin<ossia::vec3f>(slider);
117 const auto max = getMax<ossia::vec3f>(slider);
118 res[0] = from01(min[0], double(max[0]) - double(min[0]), val[0]);
119 res[1] = from01(min[1], double(max[1]) - double(min[1]), val[1]);
120 res[2] = from01(min[2], double(max[2]) - double(min[2]), val[2]);
121 return res;
122 }
123
124 template <typename T>
125 static std::array<double, 4> to01(const T& slider, ossia::vec4f val) noexcept
126 {
127 std::array<double, 4> res;
128 const auto min = getMin<ossia::vec4f>(slider);
129 const auto max = getMax<ossia::vec4f>(slider);
130 res[0] = to01(min[0], double(max[0]) - double(min[0]), val[0]);
131 res[1] = to01(min[1], double(max[1]) - double(min[1]), val[1]);
132 res[2] = to01(min[2], double(max[2]) - double(min[2]), val[2]);
133 res[3] = to01(min[3], double(max[3]) - double(min[3]), val[3]);
134 return res;
135 }
136
137 template <typename T>
138 static ossia::vec4f from01(const T& slider, std::array<double, 4> val) noexcept
139 {
140 ossia::vec4f res;
141 const auto min = getMin<ossia::vec4f>(slider);
142 const auto max = getMax<ossia::vec4f>(slider);
143 res[0] = from01(min[0], double(max[0]) - double(min[0]), val[0]);
144 res[1] = from01(min[1], double(max[1]) - double(min[1]), val[1]);
145 res[2] = from01(min[2], double(max[2]) - double(min[2]), val[2]);
146 res[3] = from01(min[3], double(max[3]) - double(min[3]), val[3]);
147 return res;
148 }
149
150 template <typename T, std::size_t N>
151 static std::array<float, N> from01(const T& slider, std::array<double, N> val) noexcept
152 {
153 std::array<float, N> res;
154 const auto min = getMin<std::array<double, N>>(slider);
155 const auto max = getMax<std::array<double, N>>(slider);
156 for(std::size_t i = 0; i < N; i++)
157 res[i] = from01(min[i], double(max[i]) - double(min[i]), val[i]);
158 return res;
159 }
160};
161
163{
164 static double to01(double min, double range, double val) noexcept
165 {
166 return ossia::log_to_normalized(min, range, val);
167 }
168
169 static double from01(double min, double range, double val) noexcept
170 {
171 return ossia::normalized_to_log(min, range, val);
172 }
173
174 template <typename T>
175 static double to01(const T& slider, double val) noexcept
176 {
177 auto min = getMin<double>(slider);
178 auto max = getMax<double>(slider);
179 if(max - min == 0)
180 max = min + 1;
181 return to01(min, max - min, val);
182 }
183
184 template <typename T>
185 static double from01(const T& slider, double val) noexcept
186 {
187 auto min = getMin<double>(slider);
188 auto max = getMax<double>(slider);
189 if(max - min == 0)
190 max = min + 1;
191 return from01(min, max - min, val);
192 }
193};
194
198template <typename Mapper>
200{
201 static double to01(double min, double range, double val) noexcept
202 {
203 return Mapper::map(ossia::clamp((val - min) / range, 0., 1.));
204 }
205
206 static double from01(double min, double range, double val) noexcept
207 {
208 return min + Mapper::unmap(ossia::clamp(val, 0., 1.)) * range;
209 }
210
211 template <typename T>
212 static double to01(const T& slider, double val) noexcept
213 {
214 auto min = getMin<double>(slider);
215 auto max = getMax<double>(slider);
216 if(max - min == 0)
217 max = min + 1;
218 return to01(min, max - min, val);
219 }
220
221 template <typename T>
222 static double from01(const T& slider, double val) noexcept
223 {
224 auto min = getMin<double>(slider);
225 auto max = getMax<double>(slider);
226 if(max - min == 0)
227 max = min + 1;
228 return from01(min, max - min, val);
229 }
230};
231
232template <typename Norm_T>
234{
235 double min{};
236 double max{};
237 template <typename T>
238 FixedNormalizer(const T& slider)
239 {
240 min = getMin<double>(slider);
241 max = getMax<double>(slider);
242 if(max - min == 0)
243 max = min + 1;
244 }
245
246 constexpr double to01(double val) const noexcept
247 {
248 return Norm_T::to01(min, max - min, val);
249 }
250
251 constexpr double from01(double val) const noexcept
252 {
253 return Norm_T::from01(min, max - min, val);
254 }
255};
256
257template <typename Norm_T, typename Slider_T>
259{
260 const Slider_T& slider;
261
262 UpdatingNormalizer(const Slider_T& sl)
263 : slider{sl}
264 {
265 }
266
267 constexpr double to01(double val) const noexcept { return Norm_T::to01(slider, val); }
268
269 constexpr double from01(double val) const noexcept
270 {
271 return Norm_T::from01(slider, val);
272 }
273};
274
275template <typename Control_T, typename Widget_T>
276static void initWidgetProperties(Control_T& inlet, Widget_T& widget)
277{
278 if constexpr(requires { widget.setNoValueChangeOnMove(true); })
279 widget.setNoValueChangeOnMove(inlet.noValueChangeOnMove);
280}
281
282template <typename Widget_T>
283static void setRange(Widget_T& widget, auto&& min, auto&& max, auto&& init)
284{
285 widget.setRange(min, max, init);
286}
287
288static inline void setRange(QSpinBox& widget, auto&& min, auto&& max, auto&& init)
289{
290 widget.setRange(min, max);
291}
292
293static inline void setRange(QDoubleSpinBox& widget, auto&& min, auto&& max, auto&& init)
294{
295 widget.setRange(min, max);
296}
297
298template <typename T, typename Control_T, typename Widget_T>
299static void bindFloatDomain(const T& slider, Control_T& inlet, Widget_T& widget)
300{
301 auto min = getMin<float>(slider);
302 auto max = getMax<float>(slider);
303 if(max - min == 0)
304 max = min + 1;
305
306 setRange(widget, min, max, getInit<float>(slider));
307
308 if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
309 {
310 SCORE_ASSERT(&slider == &inlet);
311 QObject::connect(&inlet, &Control_T::domainChanged, &widget, [&slider, &widget] {
312 auto min = getMin<float>(slider);
313 auto max = getMax<float>(slider);
314 if(max - min == 0)
315 max = min + 1;
316
317 setRange(widget, min, max, getInit<float>(slider));
318 });
319 }
320}
321
322template <typename T, typename Control_T, typename Widget_T>
323static void bindIntDomain(const T& slider, Control_T& inlet, Widget_T& widget)
324{
325 auto min = getMin<int>(slider);
326 auto max = getMax<int>(slider);
327 if(max - min == 0)
328 max = min + 1;
329
330 setRange(widget, min, max, getInit<int>(slider));
331
332 if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
333 {
334 SCORE_ASSERT(&slider == &inlet);
335 QObject::connect(&inlet, &Control_T::domainChanged, &widget, [&slider, &widget] {
336 auto min = getMin<int>(slider);
337 auto max = getMax<int>(slider);
338 if(max - min == 0)
339 max = min + 1;
340
341 setRange(widget, min, max, getInit<int>(slider));
342 });
343 }
344}
345
346template <typename T, typename Control_T, typename Widget_T>
347static void bindVec2Domain(const T& slider, Control_T& inlet, Widget_T& widget)
348{
349 auto update_range = [&widget, &inlet, &slider] {
350 auto min = ossia::get_min(inlet.domain());
351 auto max = ossia::get_max(inlet.domain());
352 auto min_float = min.template target<float>();
353 auto max_float = max.template target<float>();
354 if(min_float && max_float)
355 {
356 if(*max_float - *min_float == 0)
357 *max_float = *min_float + 1;
358 widget.setRange(
359 {*min_float, *min_float}, {*max_float, *max_float}, {*min_float, *min_float});
360 }
361 else
362 {
363 auto min_vec2 = min.template target<ossia::vec2f>();
364 auto max_vec2 = max.template target<ossia::vec2f>();
365 if(min_vec2 && max_vec2)
366 {
367 auto& min = *min_vec2;
368 auto& max = *max_vec2;
369 for(std::size_t i = 0; i < min.size(); i++)
370 {
371 if(max[i] - min[i] == 0)
372 max[i] = min[i] + 1;
373 }
374
375 auto init_vec2 = getInit<ossia::vec2f>(slider);
376 widget.setRange(min, max, init_vec2);
377 }
378 }
379 };
380
381 update_range();
382
383 if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
384 {
385 SCORE_ASSERT(&slider == &inlet);
386 QObject::connect(&inlet, &Control_T::domainChanged, &widget, update_range);
387 }
388}
389
390template <typename T, typename Control_T, typename Widget_T>
391static void bindVec3Domain(const T& slider, Control_T& inlet, Widget_T& widget)
392{
393 auto update_range = [&widget, &inlet, &slider] {
394 auto min = ossia::get_min(inlet.domain());
395 auto max = ossia::get_max(inlet.domain());
396 auto min_float = min.template target<float>();
397 auto max_float = max.template target<float>();
398 if(min_float && max_float)
399 {
400 if(*max_float - *min_float == 0)
401 *max_float = *min_float + 1;
402 widget.setRange(
403 {*min_float, *min_float, *min_float}, {*max_float, *max_float, *max_float});
404 }
405 else
406 {
407 auto min_vec3 = min.template target<ossia::vec3f>();
408 auto max_vec3 = max.template target<ossia::vec3f>();
409 if(min_vec3 && max_vec3)
410 {
411 auto& min = *min_vec3;
412 auto& max = *max_vec3;
413 for(std::size_t i = 0; i < min.size(); i++)
414 {
415 if(max[i] - min[i] == 0)
416 max[i] = min[i] + 1;
417 }
418
419 auto init_vec3 = getInit<ossia::vec3f>(slider);
420 widget.setRange(min, max, init_vec3);
421 }
422 }
423 };
424
425 update_range();
426
427 if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
428 {
429 SCORE_ASSERT(&slider == &inlet);
430 QObject::connect(&inlet, &Control_T::domainChanged, &widget, update_range);
431 }
432}
433}
Definition ControlWidgetDomains.hpp:234
Definition ControlWidgetDomains.hpp:47
Definition ControlWidgetDomains.hpp:163
Definition ControlWidgetDomains.hpp:200
Definition ControlWidgetDomains.hpp:259
Definition MIDISync.hpp:149