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 
14 namespace WidgetFactory
15 {
16 
17 template <typename T>
18 static 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 
26 template <typename T>
27 static 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 
35 template <typename T>
36 static 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 
194 template <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 
219 template <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 
237 template <typename Control_T, typename Widget_T>
238 static void initWidgetProperties(Control_T& inlet, Widget_T& widget)
239 {
240  if constexpr(requires { widget.setNoValueChangeOnMove(true); })
241  widget.setNoValueChangeOnMove(inlet.noValueChangeOnMove);
242 }
243 
244 template <typename Widget_T>
245 static void setRange(Widget_T& widget, auto&& min, auto&& max, auto&& init)
246 {
247  widget.setRange(min, max, init);
248 }
249 
250 static inline void setRange(QSpinBox& widget, auto&& min, auto&& max, auto&& init)
251 {
252  widget.setRange(min, max);
253 }
254 
255 static inline void setRange(QDoubleSpinBox& widget, auto&& min, auto&& max, auto&& init)
256 {
257  widget.setRange(min, max);
258 }
259 
260 template <typename T, typename Control_T, typename Widget_T>
261 static 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 
284 template <typename T, typename Control_T, typename Widget_T>
285 static 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 
308 template <typename T, typename Control_T, typename Widget_T>
309 static 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 
352 template <typename T, typename Control_T, typename Widget_T>
353 static 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: LFO_v2.hpp:68