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 };
150 
152 {
153  static double to01(double min, double range, double val) noexcept
154  {
155  return ossia::log_to_normalized(min, range, val);
156  }
157 
158  static double from01(double min, double range, double val) noexcept
159  {
160  return ossia::normalized_to_log(min, range, val);
161  }
162 
163  template <typename T>
164  static double to01(const T& slider, double val) noexcept
165  {
166  auto min = getMin<double>(slider);
167  auto max = getMax<double>(slider);
168  if(max - min == 0)
169  max = min + 1;
170  return to01(min, max - min, val);
171  }
172 
173  template <typename T>
174  static double from01(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 from01(min, max - min, val);
181  }
182 };
183 
184 template <typename Norm_T>
186 {
187  double min{};
188  double max{};
189  template <typename T>
190  FixedNormalizer(const T& slider)
191  {
192  min = getMin<double>(slider);
193  max = getMax<double>(slider);
194  if(max - min == 0)
195  max = min + 1;
196  }
197 
198  constexpr double to01(double val) const noexcept
199  {
200  return Norm_T::to01(min, max - min, val);
201  }
202 
203  constexpr double from01(double val) const noexcept
204  {
205  return Norm_T::from01(min, max - min, val);
206  }
207 };
208 
209 template <typename Norm_T, typename Slider_T>
211 {
212  const Slider_T& slider;
213 
214  UpdatingNormalizer(const Slider_T& sl)
215  : slider{sl}
216  {
217  }
218 
219  constexpr double to01(double val) const noexcept { return Norm_T::to01(slider, val); }
220 
221  constexpr double from01(double val) const noexcept
222  {
223  return Norm_T::from01(slider, val);
224  }
225 };
226 
227 template <typename Control_T, typename Widget_T>
228 static void initWidgetProperties(Control_T& inlet, Widget_T& widget)
229 {
230  if constexpr(requires { widget.setNoValueChangeOnMove(true); })
231  widget.setNoValueChangeOnMove(inlet.noValueChangeOnMove);
232 }
233 
234 template <typename Widget_T>
235 static void setRange(Widget_T& widget, auto&& min, auto&& max, auto&& init)
236 {
237  widget.setRange(min, max, init);
238 }
239 
240 static inline void setRange(QSpinBox& widget, auto&& min, auto&& max, auto&& init)
241 {
242  widget.setRange(min, max);
243 }
244 
245 static inline void setRange(QDoubleSpinBox& widget, auto&& min, auto&& max, auto&& init)
246 {
247  widget.setRange(min, max);
248 }
249 
250 template <typename T, typename Control_T, typename Widget_T>
251 static void bindFloatDomain(const T& slider, Control_T& inlet, Widget_T& widget)
252 {
253  auto min = getMin<float>(slider);
254  auto max = getMax<float>(slider);
255  if(max - min == 0)
256  max = min + 1;
257 
258  setRange(widget, min, max, getInit<float>(slider));
259 
260  if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
261  {
262  SCORE_ASSERT(&slider == &inlet);
263  QObject::connect(&inlet, &Control_T::domainChanged, &widget, [&slider, &widget] {
264  auto min = getMin<float>(slider);
265  auto max = getMax<float>(slider);
266  if(max - min == 0)
267  max = min + 1;
268 
269  setRange(widget, min, max, getInit<float>(slider));
270  });
271  }
272 }
273 
274 template <typename T, typename Control_T, typename Widget_T>
275 static void bindIntDomain(const T& slider, Control_T& inlet, Widget_T& widget)
276 {
277  auto min = getMin<int>(slider);
278  auto max = getMax<int>(slider);
279  if(max - min == 0)
280  max = min + 1;
281 
282  setRange(widget, min, max, getInit<int>(slider));
283 
284  if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
285  {
286  SCORE_ASSERT(&slider == &inlet);
287  QObject::connect(&inlet, &Control_T::domainChanged, &widget, [&slider, &widget] {
288  auto min = getMin<int>(slider);
289  auto max = getMax<int>(slider);
290  if(max - min == 0)
291  max = min + 1;
292 
293  setRange(widget, min, max, getInit<int>(slider));
294  });
295  }
296 }
297 
298 template <typename T, typename Control_T, typename Widget_T>
299 static void bindVec2Domain(const T& slider, Control_T& inlet, Widget_T& widget)
300 {
301  auto update_range = [&widget, &inlet, &slider] {
302  auto min = ossia::get_min(inlet.domain());
303  auto max = ossia::get_max(inlet.domain());
304  auto min_float = min.template target<float>();
305  auto max_float = max.template target<float>();
306  if(min_float && max_float)
307  {
308  if(*max_float - *min_float == 0)
309  *max_float = *min_float + 1;
310  widget.setRange(
311  {*min_float, *min_float}, {*max_float, *max_float}, {*min_float, *min_float});
312  }
313  else
314  {
315  auto min_vec2 = min.template target<ossia::vec2f>();
316  auto max_vec2 = max.template target<ossia::vec2f>();
317  if(min_vec2 && max_vec2)
318  {
319  auto& min = *min_vec2;
320  auto& max = *max_vec2;
321  for(std::size_t i = 0; i < min.size(); i++)
322  {
323  if(max[i] - min[i] == 0)
324  max[i] = min[i] + 1;
325  }
326 
327  auto init_vec2 = getInit<ossia::vec2f>(slider);
328  widget.setRange(min, max, init_vec2);
329  }
330  }
331  };
332 
333  update_range();
334 
335  if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
336  {
337  SCORE_ASSERT(&slider == &inlet);
338  QObject::connect(&inlet, &Control_T::domainChanged, &widget, update_range);
339  }
340 }
341 
342 template <typename T, typename Control_T, typename Widget_T>
343 static void bindVec3Domain(const T& slider, Control_T& inlet, Widget_T& widget)
344 {
345  auto update_range = [&widget, &inlet, &slider] {
346  auto min = ossia::get_min(inlet.domain());
347  auto max = ossia::get_max(inlet.domain());
348  auto min_float = min.template target<float>();
349  auto max_float = max.template target<float>();
350  if(min_float && max_float)
351  {
352  if(*max_float - *min_float == 0)
353  *max_float = *min_float + 1;
354  widget.setRange(
355  {*min_float, *min_float, *min_float}, {*max_float, *max_float, *max_float});
356  }
357  else
358  {
359  auto min_vec3 = min.template target<ossia::vec3f>();
360  auto max_vec3 = max.template target<ossia::vec3f>();
361  if(min_vec3 && max_vec3)
362  {
363  auto& min = *min_vec3;
364  auto& max = *max_vec3;
365  for(std::size_t i = 0; i < min.size(); i++)
366  {
367  if(max[i] - min[i] == 0)
368  max[i] = min[i] + 1;
369  }
370 
371  auto init_vec3 = getInit<ossia::vec3f>(slider);
372  widget.setRange(min, max, init_vec3);
373  }
374  }
375  };
376 
377  update_range();
378 
379  if constexpr(std::is_base_of_v<Process::ControlInlet, T>)
380  {
381  SCORE_ASSERT(&slider == &inlet);
382  QObject::connect(&inlet, &Control_T::domainChanged, &widget, update_range);
383  }
384 }
385 }
Definition: ControlWidgetDomains.hpp:186
Definition: ControlWidgetDomains.hpp:47
Definition: ControlWidgetDomains.hpp:152
Definition: ControlWidgetDomains.hpp:211
Definition: LFO_v2.hpp:68