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 ossia::vec2f to01(const T& slider, ossia::vec2f val) noexcept
80 {
81 ossia::vec2f res;
82 const auto min = getMin<ossia::vec2f>(slider);
83 const auto max = getMax<ossia::vec2f>(slider);
84 res[0] = to01(min[0], max[0] - min[0], val[0]);
85 res[1] = to01(min[1], max[1] - min[1], val[1]);
86 return res;
87 }
88
89 template <typename T>
90 static ossia::vec2f from01(const T& slider, ossia::vec2f 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], max[0] - min[0], val[0]);
96 res[1] = from01(min[1], max[1] - min[1], val[1]);
97 return res;
98 }
99
100 template <typename T>
101 static ossia::vec3f to01(const T& slider, ossia::vec3f val) noexcept
102 {
103 ossia::vec3f res;
104 const auto min = getMin<ossia::vec3f>(slider);
105 const auto max = getMax<ossia::vec3f>(slider);
106 res[0] = to01(min[0], max[0] - min[0], val[0]);
107 res[1] = to01(min[1], max[1] - min[1], val[1]);
108 res[2] = to01(min[2], max[2] - min[2], val[2]);
109 return res;
110 }
111
112 template <typename T>
113 static ossia::vec3f from01(const T& slider, ossia::vec3f 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], max[0] - min[0], val[0]);
119 res[1] = from01(min[1], max[1] - min[1], val[1]);
120 res[2] = from01(min[2], max[2] - min[2], val[2]);
121 return res;
122 }
123
124 template <typename T>
125 static ossia::vec4f to01(const T& slider, ossia::vec4f val) noexcept
126 {
127 ossia::vec4f res;
128 const auto min = getMin<ossia::vec4f>(slider);
129 const auto max = getMax<ossia::vec4f>(slider);
130 res[0] = to01(min[0], max[0] - min[0], val[0]);
131 res[1] = to01(min[1], max[1] - min[1], val[1]);
132 res[2] = to01(min[2], max[2] - min[2], val[2]);
133 res[3] = to01(min[3], max[3] - min[3], val[3]);
134 return res;
135 }
136
137 template <typename T>
138 static ossia::vec4f from01(const T& slider, ossia::vec4f 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], max[0] - min[0], val[0]);
144 res[1] = from01(min[1], max[1] - min[1], val[1]);
145 res[2] = from01(min[2], max[2] - min[2], val[2]);
146 res[3] = from01(min[3], max[3] - min[3], val[3]);
147 return res;
148 }
149 template <typename T, std::size_t N>
150 static std::array<float, N> from01(const T& slider, std::array<double, N> val) noexcept
151 {
152 std::array<float, N> res;
153 const auto min = getMin<std::array<double, N>>(slider);
154 const auto max = getMax<std::array<double, N>>(slider);
155 for(int i = 0; i < N; i++)
156 res[i] = from01(min[i], max[i] - min[i], val[i]);
157 return res;
158 }
159};
160
162{
163 static double to01(double min, double range, double val) noexcept
164 {
165 return ossia::log_to_normalized(min, range, val);
166 }
167
168 static double from01(double min, double range, double val) noexcept
169 {
170 return ossia::normalized_to_log(min, range, val);
171 }
172
173 template <typename T>
174 static double to01(const T& slider, double val) noexcept
175 {
176 auto min = getMin<double>(slider);
177 auto max = getMax<double>(slider);
178 if(max - min == 0)
179 max = min + 1;
180 return to01(min, max - min, val);
181 }
182
183 template <typename T>
184 static double from01(const T& slider, double val) noexcept
185 {
186 auto min = getMin<double>(slider);
187 auto max = getMax<double>(slider);
188 if(max - min == 0)
189 max = min + 1;
190 return from01(min, max - min, val);
191 }
192};
193
194template <typename Norm_T>
196{
197 double min{};
198 double max{};
199 template <typename T>
200 FixedNormalizer(const T& slider)
201 {
202 min = getMin<double>(slider);
203 max = getMax<double>(slider);
204 if(max - min == 0)
205 max = min + 1;
206 }
207
208 constexpr double to01(double val) const noexcept
209 {
210 return Norm_T::to01(min, max - min, val);
211 }
212
213 constexpr double from01(double val) const noexcept
214 {
215 return Norm_T::from01(min, max - min, val);
216 }
217};
218
219template <typename Norm_T, typename Slider_T>
221{
222 const Slider_T& slider;
223
224 UpdatingNormalizer(const Slider_T& sl)
225 : slider{sl}
226 {
227 }
228
229 constexpr double to01(double val) const noexcept { return Norm_T::to01(slider, val); }
230
231 constexpr double from01(double val) const noexcept
232 {
233 return Norm_T::from01(slider, val);
234 }
235};
236
237template <typename Control_T, typename Widget_T>
238static void initWidgetProperties(Control_T& inlet, Widget_T& widget)
239{
240 if constexpr(requires { widget.setNoValueChangeOnMove(true); })
241 widget.setNoValueChangeOnMove(inlet.noValueChangeOnMove);
242}
243
244template <typename Widget_T>
245static void setRange(Widget_T& widget, auto&& min, auto&& max, auto&& init)
246{
247 widget.setRange(min, max, init);
248}
249
250static inline void setRange(QSpinBox& widget, auto&& min, auto&& max, auto&& init)
251{
252 widget.setRange(min, max);
253}
254
255static inline void setRange(QDoubleSpinBox& widget, auto&& min, auto&& max, auto&& init)
256{
257 widget.setRange(min, max);
258}
259
260template <typename T, typename Control_T, typename Widget_T>
261static void bindFloatDomain(const T& slider, Control_T& inlet, Widget_T& widget)
262{
263 auto min = getMin<float>(slider);
264 auto max = getMax<float>(slider);
265 if(max - min == 0)
266 max = min + 1;
267
268 setRange(widget, min, max, getInit<float>(slider));
269
270 if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
271 {
272 SCORE_ASSERT(&slider == &inlet);
273 QObject::connect(&inlet, &Control_T::domainChanged, &widget, [&slider, &widget] {
274 auto min = getMin<float>(slider);
275 auto max = getMax<float>(slider);
276 if(max - min == 0)
277 max = min + 1;
278
279 setRange(widget, min, max, getInit<float>(slider));
280 });
281 }
282}
283
284template <typename T, typename Control_T, typename Widget_T>
285static void bindIntDomain(const T& slider, Control_T& inlet, Widget_T& widget)
286{
287 auto min = getMin<int>(slider);
288 auto max = getMax<int>(slider);
289 if(max - min == 0)
290 max = min + 1;
291
292 setRange(widget, min, max, getInit<int>(slider));
293
294 if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
295 {
296 SCORE_ASSERT(&slider == &inlet);
297 QObject::connect(&inlet, &Control_T::domainChanged, &widget, [&slider, &widget] {
298 auto min = getMin<int>(slider);
299 auto max = getMax<int>(slider);
300 if(max - min == 0)
301 max = min + 1;
302
303 setRange(widget, min, max, getInit<int>(slider));
304 });
305 }
306}
307
308template <typename T, typename Control_T, typename Widget_T>
309static void bindVec2Domain(const T& slider, Control_T& inlet, Widget_T& widget)
310{
311 auto update_range = [&widget, &inlet, &slider] {
312 auto min = ossia::get_min(inlet.domain());
313 auto max = ossia::get_max(inlet.domain());
314 auto min_float = min.template target<float>();
315 auto max_float = max.template target<float>();
316 if(min_float && max_float)
317 {
318 if(*max_float - *min_float == 0)
319 *max_float = *min_float + 1;
320 widget.setRange(
321 {*min_float, *min_float}, {*max_float, *max_float}, {*min_float, *min_float});
322 }
323 else
324 {
325 auto min_vec2 = min.template target<ossia::vec2f>();
326 auto max_vec2 = max.template target<ossia::vec2f>();
327 if(min_vec2 && max_vec2)
328 {
329 auto& min = *min_vec2;
330 auto& max = *max_vec2;
331 for(std::size_t i = 0; i < min.size(); i++)
332 {
333 if(max[i] - min[i] == 0)
334 max[i] = min[i] + 1;
335 }
336
337 auto init_vec2 = getInit<ossia::vec2f>(slider);
338 widget.setRange(min, max, init_vec2);
339 }
340 }
341 };
342
343 update_range();
344
345 if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
346 {
347 SCORE_ASSERT(&slider == &inlet);
348 QObject::connect(&inlet, &Control_T::domainChanged, &widget, update_range);
349 }
350}
351
352template <typename T, typename Control_T, typename Widget_T>
353static void bindVec3Domain(const T& slider, Control_T& inlet, Widget_T& widget)
354{
355 auto update_range = [&widget, &inlet, &slider] {
356 auto min = ossia::get_min(inlet.domain());
357 auto max = ossia::get_max(inlet.domain());
358 auto min_float = min.template target<float>();
359 auto max_float = max.template target<float>();
360 if(min_float && max_float)
361 {
362 if(*max_float - *min_float == 0)
363 *max_float = *min_float + 1;
364 widget.setRange(
365 {*min_float, *min_float, *min_float}, {*max_float, *max_float, *max_float});
366 }
367 else
368 {
369 auto min_vec3 = min.template target<ossia::vec3f>();
370 auto max_vec3 = max.template target<ossia::vec3f>();
371 if(min_vec3 && max_vec3)
372 {
373 auto& min = *min_vec3;
374 auto& max = *max_vec3;
375 for(std::size_t i = 0; i < min.size(); i++)
376 {
377 if(max[i] - min[i] == 0)
378 max[i] = min[i] + 1;
379 }
380
381 auto init_vec3 = getInit<ossia::vec3f>(slider);
382 widget.setRange(min, max, init_vec3);
383 }
384 }
385 };
386
387 update_range();
388
389 if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
390 {
391 SCORE_ASSERT(&slider == &inlet);
392 QObject::connect(&inlet, &Control_T::domainChanged, &widget, update_range);
393 }
394}
395}
Definition ControlWidgetDomains.hpp:196
Definition ControlWidgetDomains.hpp:47
Definition ControlWidgetDomains.hpp:162
Definition ControlWidgetDomains.hpp:221
Definition MIDISync.hpp:126