plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp
1 #pragma once
2 #include <Process/Commands/SetControlValue.hpp>
3 #include <Process/Dataflow/ControlWidgetDomains.hpp>
4 #include <Process/Dataflow/Port.hpp>
5 #include <Process/Dataflow/TimeSignature.hpp>
6 #include <Process/Dataflow/WidgetInlets.hpp>
7 #include <Process/Script/ScriptEditor.hpp>
8 
9 #include <score/command/Dispatchers/CommandDispatcher.hpp>
10 #include <score/document/DocumentContext.hpp>
11 #include <score/graphics/GraphicWidgets.hpp>
12 #include <score/graphics/GraphicsItem.hpp>
13 #include <score/graphics/TextItem.hpp>
14 #include <score/graphics/widgets/QGraphicsMultiSlider.hpp>
15 #include <score/graphics/widgets/QGraphicsTextButton.hpp>
16 #include <score/graphics/widgets/QGraphicsXYSpinbox.hpp>
17 #include <score/graphics/widgets/QGraphicsXYZSpinbox.hpp>
18 #include <score/tools/Unused.hpp>
19 #include <score/widgets/ComboBox.hpp>
20 #include <score/widgets/ControlWidgets.hpp>
21 #include <score/widgets/SignalUtils.hpp>
22 
23 #include <ossia/detail/algorithms.hpp>
24 #include <ossia/network/domain/domain_functions.hpp>
25 #include <ossia/network/value/value_conversion.hpp>
26 
27 #include <QCheckBox>
28 #include <QFileDialog>
29 #include <QGraphicsItem>
30 #include <QGraphicsSceneDragDropEvent>
31 #include <QLineEdit>
32 #include <QPalette>
33 #include <QTextDocument>
34 
35 #include <private/qwidgettextcontrol_p.h>
36 
37 #include <score_lib_process_export.h>
38 
39 #include <verdigris>
40 namespace Process
41 {
42 
43 struct SCORE_LIB_PROCESS_EXPORT DefaultControlLayouts
44 {
45  static Process::PortItemLayout knob() noexcept;
46  static Process::PortItemLayout slider() noexcept;
47  static Process::PortItemLayout combo() noexcept;
48  static Process::PortItemLayout list() noexcept;
49  static Process::PortItemLayout lineedit() noexcept;
50  static Process::PortItemLayout spinbox() noexcept;
51  static Process::PortItemLayout toggle() noexcept;
52  static Process::PortItemLayout pad() noexcept;
53  static Process::PortItemLayout bang() noexcept;
54  static Process::PortItemLayout button() noexcept;
55  static Process::PortItemLayout chooser_toggle() noexcept;
56 };
57 
58 struct SCORE_LIB_PROCESS_EXPORT LineEditItem : public QGraphicsTextItem
59 {
60  W_OBJECT(LineEditItem)
61 public:
62  explicit LineEditItem(QGraphicsItem* parent)
63  : QGraphicsTextItem{parent}
64  {
65  setTextInteractionFlags(Qt::TextEditorInteraction);
66  auto ctl = this->findChild<QWidgetTextControl*>();
67  if(ctl)
68  {
69  ctl->setAcceptRichText(false);
70  }
71  }
72 
73  void dropEvent(QGraphicsSceneDragDropEvent* drop) override
74  {
75  QGraphicsItem::dropEvent(drop);
76  const auto& urlList = drop->mimeData()->urls();
77 
78  if(!urlList.isEmpty())
79  {
80  this->setPlainText(urlList[0].toLocalFile());
81  }
82  }
83 
84  void sizeChanged(QSizeF sz) E_SIGNAL(SCORE_LIB_PROCESS_EXPORT, sizeChanged, sz)
85 };
86 }
87 
88 namespace WidgetFactory
89 {
90 static_assert(std::numeric_limits<float>::is_iec559, "IEEE 754 required");
91 template <typename T>
92 using SetControlValue = typename std::conditional_t<
93  std::is_base_of<Process::ControlInlet, T>::value, Process::SetControlValue,
95 
96 template <typename Normalizer, typename T>
97 using ConcreteNormalizer = std::conditional_t<
98  std::is_base_of_v<Process::ControlInlet, T>
99  || std::is_base_of_v<Process::ControlOutlet, T>,
100  UpdatingNormalizer<Normalizer, T>, FixedNormalizer<Normalizer>>;
101 template <typename ControlUI, typename Normalizer, bool Control>
103 {
104  static Process::PortItemLayout layout() noexcept
105  {
106  using namespace Process;
107  if constexpr(
108  std::is_same_v<score::QGraphicsKnob, ControlUI>
109  || std::is_same_v<score::QGraphicsLogKnob, ControlUI>)
110  {
111  return DefaultControlLayouts::knob();
112  }
113  else
114  {
115  return DefaultControlLayouts::slider();
116  }
117  }
118 
119  template <typename T, typename Control_T>
120  static auto make_widget(
121  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
122  QWidget* parent, QObject* context)
123  {
124  ConcreteNormalizer<Normalizer, T> norm{slider};
125 
126  auto sl = new score::ValueDoubleSlider{parent};
127  sl->setOrientation(Qt::Horizontal);
128  sl->setContentsMargins(0, 0, 0, 0);
129  bindFloatDomain(slider, inlet, *sl);
130  sl->setValue(norm.to01(ossia::convert<double>(inlet.value())));
131 
132  if constexpr(Control)
133  {
134  QObject::connect(
135  sl, &score::DoubleSlider::sliderMoved, context,
136  [sl, norm, &inlet, &ctx](double v) {
137  sl->moving = true;
138  ctx.dispatcher.submit<SetControlValue<Control_T>>(
139  inlet, norm.from01(sl->value()));
140  });
141  QObject::connect(
142  sl, &score::DoubleSlider::sliderReleased, context, [sl, norm, &inlet, &ctx]() {
143  ctx.dispatcher.submit<SetControlValue<Control_T>>(
144  inlet, norm.from01(sl->value()));
145  ctx.dispatcher.commit();
146  sl->moving = false;
147  });
148  }
149 
150  QObject::connect(
151  &inlet, &Control_T::valueChanged, sl, [sl, norm](const ossia::value& val) {
152  if constexpr(Control)
153  {
154  if(!sl->moving)
155  sl->setValue(norm.to01(ossia::convert<double>(val)));
156  }
157  else
158  {
159  sl->setValue(norm.to01(ossia::convert<double>(val)));
160  }
161  });
162 
163  return sl;
164  }
165 
166  template <typename T, typename Control_T>
167  static auto make_item(
168  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
169  QGraphicsItem* parent, QObject* context)
170  {
171  ConcreteNormalizer<Normalizer, T> norm{slider};
172 
173  auto sl = new ControlUI{nullptr};
174  bindFloatDomain(slider, inlet, *sl);
175  sl->setValue(norm.to01(ossia::convert<double>(inlet.value())));
176 
177  if constexpr(Control)
178  {
179  QObject::connect(sl, &ControlUI::sliderMoved, context, [sl, norm, &inlet, &ctx] {
180  sl->moving = true;
181  ctx.dispatcher.submit<SetControlValue<Control_T>>(
182  inlet, norm.from01(sl->value()));
183  });
184  QObject::connect(
185  sl, &ControlUI::sliderReleased, context, [sl, norm, &inlet, &ctx] {
186  ctx.dispatcher.submit<SetControlValue<Control_T>>(
187  inlet, norm.from01(sl->value()));
188  ctx.dispatcher.commit();
189  sl->moving = false;
190  });
191  }
192 
193  QObject::connect(
194  &inlet, &Control_T::valueChanged, sl, [sl, norm](const ossia::value& val) {
195  if constexpr(Control)
196  {
197  if(!sl->moving)
198  sl->setValue(norm.to01(ossia::convert<double>(val)));
199  }
200  else
201  {
202  sl->setValue(norm.to01(ossia::convert<double>(val)));
203  }
204  });
205  QObject::connect(
206  &inlet, &Control_T::executionValueChanged, sl,
207  [sl, norm](const ossia::value& val) {
208  sl->setExecutionValue(norm.to01(ossia::convert<double>(val)));
209  });
210  QObject::connect(&inlet, &Control_T::executionReset, sl, &ControlUI::resetExecution);
211 
212  return sl;
213  }
214 };
215 
222 
223 struct IntSlider
224 {
225  static Process::PortItemLayout layout() noexcept
226  {
227  return Process::DefaultControlLayouts::slider();
228  }
229 
230  template <typename T, typename Control_T>
231  static auto make_widget(
232  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
233  QWidget* parent, QObject* context)
234  {
235  auto sl = new score::ValueSlider{parent};
236  sl->setOrientation(Qt::Horizontal);
237  bindIntDomain(slider, inlet, *sl);
238  sl->setValue(ossia::convert<int>(inlet.value()));
239  sl->setContentsMargins(0, 0, 0, 0);
240 
241  QObject::connect(
242  sl, &score::IntSlider::sliderMoved, context, [sl, &inlet, &ctx](int p) {
243  sl->moving = true;
244  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, p);
245  });
246  QObject::connect(sl, &score::IntSlider::sliderReleased, context, [sl, &inlet, &ctx] {
247  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
248  ctx.dispatcher.commit();
249  sl->moving = false;
250  });
251 
252  QObject::connect(
253  &inlet, &Control_T::valueChanged, sl, [sl](const ossia::value& val) {
254  if(!sl->moving)
255  sl->setValue(ossia::convert<int>(val));
256  });
257 
258  return sl;
259  }
260 
261  template <typename T, typename Control_T>
262  static QGraphicsItem* make_item(
263  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
264  QGraphicsItem* parent, QObject* context)
265  {
266  auto sl = new score::QGraphicsIntSlider{nullptr};
267  bindIntDomain(slider, inlet, *sl);
268  sl->setValue(ossia::convert<int>(inlet.value()));
269 
270  QObject::connect(
271  sl, &score::QGraphicsIntSlider::sliderMoved, context, [=, &inlet, &ctx] {
272  sl->moving = true;
273  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
274  });
275  QObject::connect(
276  sl, &score::QGraphicsIntSlider::sliderReleased, context, [&ctx, sl]() {
277  ctx.dispatcher.commit();
278  sl->moving = false;
279  });
280 
281  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
282  if(!sl->moving)
283  sl->setValue(ossia::convert<int>(val));
284  });
285  QObject::connect(
286  &inlet, &Control_T::executionValueChanged, sl, [=](const ossia::value& val) {
287  sl->setExecutionValue(ossia::convert<int>(val));
288  });
289  QObject::connect(
290  &inlet, &Control_T::executionReset, sl,
291  &score::QGraphicsIntSlider::resetExecution);
292 
293  return sl;
294  }
295 };
296 
298 {
299  static Process::PortItemLayout layout() noexcept
300  {
301  return Process::DefaultControlLayouts::slider();
302  }
303 
304  template <typename T, typename Control_T>
305  static auto make_widget(
306  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
307  QWidget* parent, QObject* context)
308  {
309  // TODO
310  return nullptr;
311  }
312 
313  template <typename T, typename Control_T>
314  static QGraphicsItem* make_item(
315  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
316  QGraphicsItem* parent, QObject* context)
317  {
318  auto sl = new score::QGraphicsRangeSlider{parent};
319  bindIntDomain(slider, inlet, *sl);
320  sl->setValue(ossia::convert<ossia::vec2f>(inlet.value()));
321 
322  QObject::connect(
323  sl, &score::QGraphicsRangeSlider::sliderMoved, context, [=, &inlet, &ctx] {
324  sl->moving = true;
325  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
326  });
327  QObject::connect(
328  sl, &score::QGraphicsRangeSlider::sliderReleased, context, [&ctx, sl]() {
329  ctx.dispatcher.commit();
330  sl->moving = false;
331  });
332 
333  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
334  if(!sl->moving)
335  sl->setValue(ossia::convert<ossia::vec2f>(val));
336  });
337  QObject::connect(
338  &inlet, &Control_T::executionValueChanged, sl, [=](const ossia::value& val) {
339  // TODO
340  // sl->setExecutionValue(ossia::convert<ossia::vec2f>(val));
341  });
342  QObject::connect(
343  &inlet, &Control_T::executionReset, sl,
344  &score::QGraphicsRangeSlider::resetExecution);
345 
346  return sl;
347  }
348 };
350 {
351  static Process::PortItemLayout layout() noexcept
352  {
353  return Process::DefaultControlLayouts::slider();
354  }
355 
356  template <typename T, typename Control_T>
357  static auto make_widget(
358  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
359  QWidget* parent, QObject* context)
360  {
361  // TODO
362  return nullptr;
363  }
364 
365  template <typename T, typename Control_T>
366  static QGraphicsItem* make_item(
367  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
368  QGraphicsItem* parent, QObject* context)
369  {
370  auto sl = new score::QGraphicsRangeSlider{parent};
371  bindFloatDomain(slider, inlet, *sl);
372  sl->setValue(ossia::convert<ossia::vec2f>(inlet.value()));
373 
374  QObject::connect(
375  sl, &score::QGraphicsRangeSlider::sliderMoved, context, [=, &inlet, &ctx] {
376  sl->moving = true;
377  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
378  });
379  QObject::connect(
380  sl, &score::QGraphicsRangeSlider::sliderReleased, context, [&ctx, sl]() {
381  ctx.dispatcher.commit();
382  sl->moving = false;
383  });
384 
385  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
386  if(!sl->moving)
387  sl->setValue(ossia::convert<ossia::vec2f>(val));
388  });
389  QObject::connect(
390  &inlet, &Control_T::executionValueChanged, sl, [=](const ossia::value& val) {
391  // TODO
392  // sl->setExecutionValue(ossia::convert<ossia::vec2f>(val));
393  });
394  QObject::connect(
395  &inlet, &Control_T::executionReset, sl,
396  &score::QGraphicsRangeSlider::resetExecution);
397 
398  return sl;
399  }
400 };
402 {
403  static Process::PortItemLayout layout() noexcept
404  {
405  return Process::DefaultControlLayouts::pad();
406  }
407 
408  template <typename T, typename Control_T>
409  static auto make_widget(
410  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
411  QWidget* parent, QObject* context)
412  {
413  SCORE_TODO;
414  return nullptr; // TODO
415  }
416 
417  template <typename T, typename Control_T>
418  static QGraphicsItem* make_item(
419  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
420  QGraphicsItem* parent, QObject* context)
421  {
422  auto sl = new score::QGraphicsXYSpinboxChooser{true, nullptr};
423  bindVec2Domain(slider, inlet, *sl);
424  sl->setValue(
425  LinearNormalizer::to01(*sl, ossia::convert<ossia::vec2f>(inlet.value())));
426 
427  QObject::connect(
428  sl, &score::QGraphicsXYSpinboxChooser::sliderMoved, context, [=, &inlet, &ctx] {
429  sl->moving = true;
430  ctx.dispatcher.submit<SetControlValue<Control_T>>(
431  inlet, LinearNormalizer::from01(*sl, sl->value()));
432  });
433  QObject::connect(
434  sl, &score::QGraphicsXYSpinboxChooser::sliderReleased, context, [&ctx, sl]() {
435  ctx.dispatcher.commit();
436  sl->moving = false;
437  });
438 
439  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
440  if(!sl->moving)
441  sl->setValue(LinearNormalizer::to01(*sl, ossia::convert<ossia::vec2f>(val)));
442  });
443 
444  return sl;
445  }
446 };
447 
449 {
450  static Process::PortItemLayout layout() noexcept
451  {
452  return Process::DefaultControlLayouts::spinbox();
453  }
454 
455  template <typename T, typename Control_T>
456  static auto make_widget(
457  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
458  QWidget* parent, QObject* context)
459  {
460  auto sl = new QSpinBox{parent};
461  bindIntDomain(slider, inlet, *sl);
462  sl->setValue(ossia::convert<int>(inlet.value()));
463  sl->setContentsMargins(0, 0, 0, 0);
464 
465  QObject::connect(
466  sl, SignalUtils::QSpinBox_valueChanged_int(), context, [&inlet, &ctx](int val) {
467  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
468  inlet, val);
469  });
470 
471  QObject::connect(
472  &inlet, &Control_T::valueChanged, sl,
473  [sl](const ossia::value& val) { sl->setValue(ossia::convert<int>(val)); });
474 
475  return sl;
476  }
477 
478  template <typename T, typename Control_T>
479  static QGraphicsItem* make_item(
480  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
481  QGraphicsItem* parent, QObject* context)
482  {
483  auto sl = new score::QGraphicsIntSpinbox{nullptr};
484  bindIntDomain(slider, inlet, *sl);
485  sl->setValue(ossia::convert<int>(inlet.value()));
486 
487  QObject::connect(
488  sl, &score::QGraphicsIntSpinbox::sliderMoved, context, [=, &inlet, &ctx] {
489  sl->moving = true;
490  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
491  });
492  QObject::connect(
493  sl, &score::QGraphicsIntSpinbox::sliderReleased, context, [&ctx, sl]() {
494  ctx.dispatcher.commit();
495  sl->moving = false;
496  });
497 
498  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
499  if(!sl->moving)
500  sl->setValue(ossia::convert<int>(val));
501  });
502 
503  QObject::connect(
504  &inlet, &Control_T::executionValueChanged, sl, [=](const ossia::value& val) {
505  if(!sl->moving)
506  sl->setExecutionValue(ossia::convert<int>(val));
507  });
508  QObject::connect(
509  &inlet, &Control_T::executionReset, sl,
510  &score::QGraphicsIntSpinbox::resetExecution);
511 
512  return sl;
513  }
514 };
515 
517 {
518  static Process::PortItemLayout layout() noexcept
519  {
520  return Process::DefaultControlLayouts::spinbox();
521  }
522 
523  template <typename T, typename Control_T>
524  static auto make_widget(
525  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
526  QWidget* parent, QObject* context)
527  {
528  auto sl = new QDoubleSpinBox{parent};
529  bindFloatDomain(slider, inlet, *sl);
530  sl->setValue(ossia::convert<float>(inlet.value()));
531  sl->setContentsMargins(0, 0, 0, 0);
532 
533  QObject::connect(
534  sl, SignalUtils::QDoubleSpinBox_valueChanged_double(), context,
535  [&inlet, &ctx](double val) {
536  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
537  inlet, val);
538  });
539 
540  QObject::connect(
541  &inlet, &Control_T::valueChanged, sl,
542  [sl](const ossia::value& val) { sl->setValue(ossia::convert<float>(val)); });
543 
544  return sl;
545  }
546 
547  template <typename T, typename Control_T>
548  static QGraphicsItem* make_item(
549  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
550  QGraphicsItem* parent, QObject* context)
551  {
552  ConcreteNormalizer<LinearNormalizer, T> norm{slider};
553 
554  auto sl = new score::QGraphicsSpinbox{nullptr};
555  bindFloatDomain(slider, inlet, *sl);
556  sl->setValue(norm.to01(ossia::convert<float>(inlet.value())));
557 
558  QObject::connect(
559  sl, &score::QGraphicsSpinbox::sliderMoved, context,
560  [=, &inlet, &ctx] {
561  sl->moving = true;
562  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, norm.from01(sl->value()));
563  });
564  QObject::connect(
565  sl, &score::QGraphicsSpinbox::sliderReleased, context, [&ctx, sl]() {
566  ctx.dispatcher.commit();
567  sl->moving = false;
568  });
569 
570  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
571  if(!sl->moving)
572  sl->setValue(norm.to01(ossia::convert<float>(val)));
573  });
574 
575  QObject::connect(
576  &inlet, &Control_T::executionValueChanged, sl, [=](const ossia::value& val) {
577  if(!sl->moving)
578  sl->setExecutionValue(norm.to01(ossia::convert<float>(val)));
579  });
580  QObject::connect(
581  &inlet, &Control_T::executionReset, sl,
582  &score::QGraphicsSpinbox::resetExecution);
583 
584  return sl;
585  }
586 };
587 
589 {
590  static Process::PortItemLayout layout() noexcept
591  {
592  using namespace Process;
593  return DefaultControlLayouts::knob();
594  }
595 
596  template <typename T, typename Control_T>
597  static auto make_widget(
598  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
599  QWidget* parent, QObject* context)
600  {
601  // FIXME
602  return nullptr;
603  }
604 
605  template <typename T, typename Control_T>
606  static auto make_item(
607  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
608  QGraphicsItem* parent, QObject* context)
609  {
610  auto sl = new score::QGraphicsTimeChooser{nullptr};
611  // bindFloatDomain(slider, inlet, *sl);
612  sl->setValue(ossia::convert<ossia::vec2f>(inlet.value()));
613 
614  QObject::connect(
615  sl, &score::QGraphicsTimeChooser::sliderMoved, context, [sl, &inlet, &ctx] {
616  sl->knob.moving = true;
617  sl->combo.moving = true;
618  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
619  });
620  QObject::connect(
621  sl, &score::QGraphicsTimeChooser::sliderReleased, context, [sl, &inlet, &ctx] {
622  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
623  ctx.dispatcher.commit();
624  sl->knob.moving = false;
625  sl->combo.moving = false;
626  });
627 
628  QObject::connect(
629  &inlet, &Control_T::valueChanged, sl, [sl](const ossia::value& val) {
630  if(!sl->knob.moving && !sl->combo.moving)
631  {
632  sl->setValue(ossia::convert<ossia::vec2f>(val));
633  }
634  });
635  QObject::connect(
636  &inlet, &Control_T::executionValueChanged, sl, [sl](const ossia::value& val) {
637  sl->setExecutionValue(ossia::convert<ossia::vec2f>(val));
638  });
639  QObject::connect(
640  &inlet, &Control_T::executionReset, sl,
641  &score::QGraphicsTimeChooser::resetExecution);
642 
643  return sl;
644  }
645 };
646 
647 struct Toggle
648 {
649  static Process::PortItemLayout layout() noexcept
650  {
651  return Process::DefaultControlLayouts::toggle();
652  }
653 
654  template <typename T, typename Control_T>
655  static auto make_widget(
656  const T& toggle, Control_T& inlet, const score::DocumentContext& ctx,
657  QWidget* parent, QObject* context)
658  {
659  auto sl = new QCheckBox{parent};
660  sl->setChecked(ossia::convert<bool>(inlet.value()));
661  QObject::connect(sl, &QCheckBox::toggled, context, [&inlet, &ctx](bool val) {
662  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
663  inlet, val);
664  });
665 
666  QObject::connect(
667  &inlet, &Control_T::valueChanged, sl,
668  [sl](const ossia::value& val) { sl->setChecked(ossia::convert<bool>(val)); });
669 
670  return sl;
671  }
672 
673  template <typename T, typename Control_T>
674  static QGraphicsItem* make_item(
675  const T& toggle, Control_T& inlet, const score::DocumentContext& ctx,
676  QGraphicsItem* parent, QObject* context)
677  {
678  auto cb = new score::QGraphicsCheckBox{nullptr};
679  cb->setState(ossia::convert<bool>(inlet.value()));
680 
681  QObject::connect(
682  cb, &score::QGraphicsCheckBox::toggled, context,
683  [=, &inlet, &ctx](bool toggled) {
684  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, toggled);
685  ctx.dispatcher.commit();
686  });
687 
688  QObject::connect(
689  &inlet, &Control_T::valueChanged, cb,
690  [cb](const ossia::value& val) { cb->setState(ossia::convert<bool>(val)); });
691 
692  return cb;
693  }
694 };
695 
697 {
698  static Process::PortItemLayout layout() noexcept
699  {
700  return Process::DefaultControlLayouts::bang();
701  }
702 
703  template <typename T, typename Control_T>
704  static auto make_widget(
705  const T& slider, const Control_T& inlet, const score::DocumentContext& ctx,
706  QWidget* parent, QObject* context)
707  {
708  auto sl = new QPushButton{parent};
709  const auto& name = inlet.visualName();
710  sl->setText(name.isEmpty() ? QObject::tr("Bang") : name);
711  sl->setContentsMargins(0, 0, 0, 0);
712 
713  auto& cinlet = const_cast<Control_T&>(inlet);
714  QObject::connect(sl, &QPushButton::pressed, context, [&cinlet] {
715  cinlet.valueChanged(ossia::impulse{});
716  });
717 
718  return sl;
719  }
720 
721  template <typename T, typename Control_T>
722  static QGraphicsItem* make_item(
723  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
724  QGraphicsItem* parent, QObject* context)
725  {
726  auto toggle = new score::QGraphicsButton{nullptr};
727 
728  QObject::connect(
729  toggle, &score::QGraphicsButton::pressed, context, [=, &inlet](bool pressed) {
730  if(pressed)
731  {
732  inlet.valueChanged(ossia::impulse{});
733  }
734  });
735 
736  return toggle;
737  }
738 };
739 
740 struct Button
741 {
742  static Process::PortItemLayout layout() noexcept
743  {
744  return Process::DefaultControlLayouts::bang();
745  }
746 
747  template <typename T, typename Control_T>
748  static auto make_widget(
749  const T& slider, const Control_T& inlet, const score::DocumentContext& ctx,
750  QWidget* parent, QObject* context)
751  {
752  auto sl = new QPushButton{parent};
753  const auto& name = inlet.visualName();
754  sl->setText(name.isEmpty() ? QObject::tr("Bang") : name);
755  sl->setContentsMargins(0, 0, 0, 0);
756 
757  // TODO should we not make a command here
758  auto& cinlet = const_cast<Control_T&>(inlet);
759  QObject::connect(
760  sl, &QPushButton::pressed, context, [&cinlet] { cinlet.setValue(true); });
761  QObject::connect(
762  sl, &QPushButton::released, context, [&cinlet] { cinlet.setValue(false); });
763 
764  return sl;
765  }
766 
767  template <typename T, typename Control_T>
768  static QGraphicsItem* make_item(
769  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
770  QGraphicsItem* parent, QObject* context)
771  {
772  auto toggle = new score::QGraphicsButton{nullptr};
773 
774  QObject::connect(
775  toggle, &score::QGraphicsButton::pressed, context,
776  [=, &inlet, &ctx](bool pressed) {
777  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, pressed);
778  ctx.dispatcher.commit();
779  });
780 
781  return toggle;
782  }
783 };
784 
786 {
787  static Process::PortItemLayout layout() noexcept
788  {
789  return Process::DefaultControlLayouts::chooser_toggle();
790  }
791 
792  template <typename T>
793  static constexpr auto getAlternatives(const T& t) -> decltype(auto)
794  {
795  if constexpr(std::is_member_function_pointer_v<decltype(&T::alternatives)>)
796  {
797  return t.alternatives();
798  }
799  else
800  {
801  return t.alternatives;
802  }
803  }
804  template <typename T, typename Control_T>
805  static auto make_widget(
806  const T& control, Control_T& inlet, const score::DocumentContext& ctx,
807  QWidget* parent, QObject* context)
808  {
809 
810  const auto& alts = getAlternatives(control);
811  SCORE_ASSERT(alts.size() == 2);
812  auto toggleBtn = new score::ToggleButton{alts, parent};
813  toggleBtn->setCheckable(true);
814  bool b = ossia::convert<bool>(inlet.value());
815  if(b && !toggleBtn->isChecked())
816  toggleBtn->toggle();
817  else if(!b && toggleBtn->isChecked())
818  toggleBtn->toggle();
819 
820  QObject::connect(
821  toggleBtn, &score::ToggleButton::toggled, context, [&inlet, &ctx](bool val) {
822  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
823  inlet, val);
824  });
825 
826  QObject::connect(
827  &inlet, &Control_T::valueChanged, toggleBtn,
828  [toggleBtn](const ossia::value& val) {
829  bool b = ossia::convert<bool>(val);
830  if(b && !toggleBtn->isChecked())
831  toggleBtn->toggle();
832  else if(!b && toggleBtn->isChecked())
833  toggleBtn->toggle();
834  });
835 
836  return toggleBtn;
837  }
838 
839  template <typename T, typename Control_T>
840  static QGraphicsItem* make_item(
841  const T& control, Control_T& inlet, const score::DocumentContext& ctx,
842  QGraphicsItem* parent, QObject* context)
843  {
844  const auto& alts = getAlternatives(control);
845  SCORE_ASSERT(alts.size() == 2);
846  auto toggle = new score::QGraphicsToggle{alts[0], alts[1], nullptr};
847  toggle->setState(ossia::convert<bool>(inlet.value()));
848 
849  QObject::connect(
850  toggle, &score::QGraphicsToggle::toggled, context,
851  [=, &inlet, &ctx](bool toggled) {
852  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, toggled);
853  ctx.dispatcher.commit();
854  });
855 
856  QObject::connect(
857  &inlet, &Control_T::valueChanged, toggle, [toggle](const ossia::value& val) {
858  toggle->setState(ossia::convert<bool>(val));
859  });
860 
861  return toggle;
862  }
863 };
864 
865 struct LineEdit
866 {
867  static Process::PortItemLayout layout() noexcept
868  {
869  return Process::DefaultControlLayouts::lineedit();
870  }
871 
872  template <typename T, typename Control_T>
873  static auto make_widget(
874  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
875  QWidget* parent, QObject* context)
876  {
877  auto sl = new QLineEdit{parent};
878  sl->setText(QString::fromStdString(ossia::convert<std::string>(inlet.value())));
879  sl->setContentsMargins(0, 0, 0, 0);
880  sl->setMaximumWidth(70);
881  QObject::connect(sl, &QLineEdit::editingFinished, context, [sl, &inlet, &ctx]() {
882  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
883  inlet, sl->text().toStdString());
884  });
885 
886  QObject::connect(
887  &inlet, &Control_T::valueChanged, sl, [sl](const ossia::value& val) {
888  sl->setText(QString::fromStdString(ossia::convert<std::string>(val)));
889  });
890 
891  return sl;
892  }
893 
894  template <typename T, typename Control_T>
895  static Process::LineEditItem* make_item(
896  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
897  QGraphicsItem* parent, QObject* context)
898  {
899  auto sl = new Process::LineEditItem{parent};
900  sl->setTextWidth(180.);
901  sl->setDefaultTextColor(QColor{"#E0B01E"});
902  sl->setCursor(Qt::IBeamCursor);
903 
904  sl->setPlainText(QString::fromStdString(ossia::convert<std::string>(inlet.value())));
905 
906  auto doc = sl->document();
907  QObject::connect(
908  doc, &QTextDocument::contentsChanged, context,
909  [=, &inlet, &ctx, r = sl->boundingRect()]() mutable {
910  auto cur_str = ossia::convert<std::string>(inlet.value());
911  if(cur_str != doc->toPlainText().toStdString())
912  {
913  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
914  inlet, doc->toPlainText().toStdString());
915  }
916 
917  if(r != sl->boundingRect())
918  {
919  r = sl->boundingRect();
920  sl->sizeChanged(r.size());
921  }
922  });
923  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
924  auto str = QString::fromStdString(ossia::convert<std::string>(val));
925  if(str != doc->toPlainText())
926  doc->setPlainText(str);
927  });
928 
929  return sl;
930  }
931 };
932 
934 {
936  std::string_view language, const Process::ControlInlet& port,
937  const score::DocumentContext& ctx, QWidget* parent)
938  : ScriptDialog{language, ctx, parent}
939  , m_port{port}
940  {
941  this->setText(QString::fromStdString(ossia::convert<std::string>(port.value())));
943  &QWidget::deleteLater);
944  }
945 
946  void on_accepted() override
947  {
948  this->setError(0, QString{});
949  auto cur = ossia::convert<std::string>(m_port.value());
950  auto next = this->text().toStdString();
951  if(next != cur)
952  {
953  CommandDispatcher<>{m_context.commandStack}.submit(
954  new Process::SetControlValue{m_port, next});
955  }
956  }
957 
958  const Process::ControlInlet& m_port;
959 };
960 
962 {
963  static Process::PortItemLayout layout() noexcept
964  {
965  return Process::DefaultControlLayouts::lineedit();
966  }
967 
968  template <typename T, typename Control_T>
969  static auto make_widget(
970  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
971  QWidget* parent, QObject* context)
972  {
973  auto toggle = new QPushButton{QObject::tr("Edit..."), parent};
974  QObject::connect(toggle, &QPushButton::clicked, context, [=, &inlet, &ctx] {
975  createDialog(inlet, ctx);
976  });
977  return toggle;
978  }
979 
980  template <typename T, typename Control_T>
981  static auto make_item(
982  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
983  QGraphicsItem* parent, QObject* context)
984  {
985  auto toggle = new score::QGraphicsTextButton{QObject::tr("Edit..."), nullptr};
986 
987  QObject::connect(
988  toggle, &score::QGraphicsTextButton::pressed, context,
989  [=, &inlet, &ctx] { createDialog(inlet, ctx); });
990 
991  return toggle;
992  }
993 
994  static void
995  createDialog(const Process::ProgramEdit& inlet, const score::DocumentContext& ctx)
996  {
997  auto dial = new ProgramPortScriptDialog{inlet.language, inlet, ctx, nullptr};
998  dial->exec();
999  }
1000 };
1001 
1003 {
1004  static Process::PortItemLayout layout() noexcept
1005  {
1006  return Process::DefaultControlLayouts::lineedit();
1007  }
1008  template <typename T, typename Control_T>
1009  static auto make_widget(
1010  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1011  QWidget* parent, QObject* context)
1012  {
1013  auto sl = new QLineEdit{parent};
1014  auto act = new QAction{sl};
1015 
1016  act->setStatusTip(QObject::tr("Opening a File"));
1017  act->setIcon(QIcon(":/icons/search.png"));
1018  sl->setPlaceholderText(QObject::tr("Open File"));
1019  auto on_open = [=, &inlet] {
1020  auto filename
1021  = QFileDialog::getOpenFileName(nullptr, "Open File", {}, inlet.filters());
1022  if(filename.isEmpty())
1023  return;
1024  sl->setText(filename);
1025  };
1026 
1027  QObject::connect(sl, &QLineEdit::returnPressed, on_open);
1028  QObject::connect(act, &QAction::triggered, on_open);
1029  sl->addAction(act, QLineEdit::TrailingPosition);
1030 
1031  sl->setText(QString::fromStdString(ossia::convert<std::string>(inlet.value())));
1032  sl->setContentsMargins(0, 0, 0, 0);
1033  //sl->setMaximumWidth(70);
1034 
1035  QObject::connect(sl, &QLineEdit::editingFinished, context, [sl, &inlet, &ctx]() {
1036  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
1037  inlet, sl->text().toStdString());
1038  });
1039  QObject::connect(
1040  &inlet, &Control_T::valueChanged, sl, [sl](const ossia::value& val) {
1041  sl->setText(QString::fromStdString(ossia::convert<std::string>(val)));
1042  });
1043  return sl;
1044  }
1045 
1046  template <typename T, typename Control_T>
1047  static score::QGraphicsTextButton* make_item(
1048  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1049  QGraphicsItem* parent, QObject* context)
1050  {
1051  auto bt = new score::QGraphicsTextButton{"Choose a file...", parent};
1052  auto on_open = [&inlet, &ctx] {
1053  auto filename
1054  = QFileDialog::getOpenFileName(nullptr, "Open File", {}, inlet.filters());
1055  if(filename.isEmpty())
1056  return;
1057 
1058  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
1059  inlet, filename.toStdString());
1060  };
1061  auto on_set = [&inlet, &ctx](const QString& filename) {
1062  if(filename.isEmpty())
1063  return;
1064 
1065  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
1066  inlet, filename.toStdString());
1067  };
1068  QObject::connect(bt, &score::QGraphicsTextButton::pressed, &inlet, on_open);
1069  QObject::connect(bt, &score::QGraphicsTextButton::dropped, &inlet, on_set);
1070  auto set = [=](const ossia::value& val) {
1071  auto str = QString::fromStdString(ossia::convert<std::string>(val));
1072  if(str != bt->text())
1073  {
1074  if(!str.isEmpty())
1075  bt->setText(str.split("/").back());
1076  else
1077  bt->setText("Choose a file...");
1078  }
1079  };
1080 
1081  set(slider.value());
1082  QObject::connect(&inlet, &Control_T::valueChanged, bt, set);
1083 
1084  return bt;
1085  }
1086 };
1087 
1088 struct Enum
1089 {
1090  static Process::PortItemLayout layout() noexcept
1091  {
1092  return Process::DefaultControlLayouts::list();
1093  }
1094 
1095  static const auto& toStd(const char* const& s) { return s; }
1096  static const auto& toStd(const std::string& s) { return s; }
1097  static auto toStd(const QString& s) { return s.toStdString(); }
1098 
1099  static const auto& convert(const std::string& str, const char*) { return str; }
1100  static auto convert(const std::string& str, const QString&)
1101  {
1102  return QString::fromStdString(str);
1103  }
1104 
1105  template <typename T, typename Control_T>
1106  static auto make_widget(
1107  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1108  QWidget* parent, QObject* context)
1109  {
1110  const auto& values = slider.getValues();
1111  using val_t = std::remove_reference_t<decltype(values[0])>;
1112  auto sl = new QComboBox{parent};
1113  for(const auto& e : values)
1114  {
1115  sl->addItem(e);
1116  }
1117 
1118  auto set_index = [values, sl](const ossia::value& val) {
1119  auto v = ossia::convert<std::string>(val);
1120  auto it = ossia::find(values, convert(v, val_t{}));
1121  if(it != values.end())
1122  {
1123  sl->setCurrentIndex(std::distance(values.begin(), it));
1124  }
1125  };
1126  set_index(inlet.value());
1127 
1128  QObject::connect(
1129  sl, SignalUtils::QComboBox_currentIndexChanged_int(), context,
1130  [values, &inlet, &ctx](int idx) {
1131  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
1132  inlet, toStd(values[idx]));
1133  });
1134 
1135  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1136  set_index(val);
1137  });
1138 
1139  return sl;
1140  }
1141 
1142  template <typename T, typename Control_T>
1143  static auto make_item(
1144  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1145  QGraphicsItem* parent, QObject* context)
1146  {
1147  const auto& values = slider.getValues();
1148  using val_t = std::remove_reference_t<decltype(values[0])>;
1149 
1150  auto sl = slider.pixmaps.empty() || slider.pixmaps[0] == nullptr
1151  ? new score::QGraphicsEnum{values, nullptr}
1153  values, slider.pixmaps, nullptr};
1154 
1155  auto set_index = [values, sl](const ossia::value& val) {
1156  auto v = ossia::convert<std::string>(val);
1157  auto it = ossia::find(values, convert(v, val_t{}));
1158  if(it != values.end())
1159  {
1160  sl->setValue(std::distance(values.begin(), it));
1161  }
1162  };
1163 
1164  set_index(inlet.value());
1165 
1166  QObject::connect(
1167  sl, &score::QGraphicsEnum::currentIndexChanged, context,
1168  [sl, &inlet, &ctx](int idx) {
1169  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, toStd(sl->array[idx]));
1170  ctx.dispatcher.commit();
1171  });
1172 
1173  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1174  set_index(val);
1175  });
1176 
1177  return sl;
1178  }
1179 };
1180 
1181 struct ComboBox
1182 {
1183  static Process::PortItemLayout layout() noexcept
1184  {
1185  return Process::DefaultControlLayouts::combo();
1186  }
1187 
1188  template <typename U, typename Control_T>
1189  static auto make_widget(
1190  const U& slider, Control_T& inlet, const score::DocumentContext& ctx,
1191  QWidget* parent, QObject* context)
1192  {
1193  const auto& values = slider.getValues();
1194  auto sl = new score::ComboBox{parent};
1195  for(auto& e : values)
1196  {
1197  sl->addItem(e.first);
1198  }
1199  sl->setContentsMargins(0, 0, 0, 0);
1200 
1201  auto set_index = [values, sl](const ossia::value& val) {
1202  auto it
1203  = ossia::find_if(values, [&](const auto& pair) { return pair.second == val; });
1204  if(it != values.end())
1205  {
1206  sl->setCurrentIndex(std::distance(values.begin(), it));
1207  }
1208  };
1209  set_index(inlet.value());
1210 
1211  QObject::connect(
1212  sl, SignalUtils::QComboBox_currentIndexChanged_int(), context,
1213  [values, &inlet, &ctx](int idx) {
1214  CommandDispatcher<>{ctx.commandStack}.submit<SetControlValue<Control_T>>(
1215  inlet, values[idx].second);
1216  });
1217 
1218  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1219  set_index(val);
1220  });
1221 
1222  return sl;
1223  }
1224 
1225  template <typename U, typename Control_T>
1226  static QGraphicsItem* make_item(
1227  const U& slider, Control_T& inlet, const score::DocumentContext& ctx,
1228  QGraphicsItem* parent, QObject* context)
1229  {
1230  const auto N = slider.count();
1231 
1232  const auto& values = slider.getValues();
1233  QStringList arr;
1234  arr.reserve(N);
1235  for(std::size_t i = 0; i < N; i++)
1236  arr.push_back(values[i].first);
1237 
1238  auto sl = new score::QGraphicsCombo{arr, nullptr};
1239 
1240  auto set_index = [values, sl](const ossia::value& val) {
1241  auto it
1242  = ossia::find_if(values, [&](const auto& pair) { return pair.second == val; });
1243  if(it != values.end())
1244  {
1245  sl->setValue(std::distance(values.begin(), it));
1246  }
1247  };
1248  set_index(inlet.value());
1249 
1250  QObject::connect(
1251  sl, &score::QGraphicsCombo::sliderMoved, context, [values, sl, &inlet, &ctx] {
1252  sl->moving = true;
1253  ctx.dispatcher.submit<SetControlValue<Control_T>>(
1254  inlet, values[sl->value()].second);
1255  });
1256  QObject::connect(sl, &score::QGraphicsCombo::sliderReleased, context, [sl, &ctx] {
1257  ctx.dispatcher.commit();
1258  sl->moving = false;
1259  });
1260 
1261  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1262  if(sl->moving)
1263  return;
1264 
1265  set_index(val);
1266  });
1267 
1268  return sl;
1269  }
1270 };
1271 
1272 struct TimeSignatureValidator final : public QValidator
1273 {
1274  static constexpr Process::PortItemLayout layout() noexcept
1275  {
1276  using namespace Process;
1277  return PortItemLayout{};
1278  }
1279 
1280  using QValidator::QValidator;
1281  State validate(QString& str, int&) const override
1282  {
1283  auto p = ossia::get_time_signature(str.toStdString());
1284  if(!p)
1285  return State::Invalid;
1286 
1287  return State::Acceptable;
1288  }
1289 };
1290 
1292 {
1293  static Process::PortItemLayout layout() noexcept
1294  {
1295  return Process::DefaultControlLayouts::pad();
1296  }
1297 
1298  template <typename T, typename Control_T>
1299  static auto make_widget(
1300  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1301  QWidget* parent, QObject* context)
1302  {
1303  SCORE_TODO;
1304  return nullptr; // TODO
1305  }
1306 
1307  template <typename T, typename Control_T>
1308  static QGraphicsItem* make_item(
1309  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1310  QGraphicsItem* parent, QObject* context)
1311  {
1312  auto sl = new score::QGraphicsHSVChooser{nullptr};
1313  sl->setRgbaValue(ossia::convert<ossia::vec4f>(inlet.value()));
1314 
1315  QObject::connect(
1316  sl, &score::QGraphicsHSVChooser::sliderMoved, context, [=, &inlet, &ctx] {
1317  sl->moving = true;
1318  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->rgbaValue());
1319  });
1320  QObject::connect(
1321  sl, &score::QGraphicsHSVChooser::sliderReleased, context, [&ctx, sl]() {
1322  ctx.dispatcher.commit();
1323  sl->moving = false;
1324  });
1325 
1326  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1327  if(!sl->moving)
1328  sl->setRgbaValue(ossia::convert<ossia::vec4f>(val));
1329  });
1330 
1331  return sl;
1332  }
1333 };
1334 
1335 struct XYSlider
1336 {
1337  static constexpr Process::PortItemLayout layout() noexcept
1338  {
1339  using namespace Process;
1340  return PortItemLayout{};
1341  }
1342 
1343  template <typename T, typename Control_T>
1344  static auto make_widget(
1345  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1346  QWidget* parent, QObject* context)
1347  {
1348  SCORE_TODO;
1349  return nullptr; // TODO
1350  }
1351 
1352  template <typename T, typename Control_T>
1353  static QGraphicsItem* make_item(
1354  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1355  QGraphicsItem* parent, QObject* context)
1356  {
1357  auto sl = new score::QGraphicsXYChooser{nullptr};
1358  sl->setValue(ossia::convert<ossia::vec2f>(inlet.value()));
1359  bindVec2Domain(slider, inlet, *sl);
1360 
1361  QObject::connect(
1362  sl, &score::QGraphicsXYChooser::sliderMoved, context, [=, &inlet, &ctx] {
1363  sl->moving = true;
1364  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
1365  });
1366  QObject::connect(
1367  sl, &score::QGraphicsXYChooser::sliderReleased, context, [&ctx, sl]() {
1368  ctx.dispatcher.commit();
1369  sl->moving = false;
1370  });
1371 
1372  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1373  if(!sl->moving)
1374  sl->setValue(ossia::convert<ossia::vec2f>(val));
1375  });
1376 
1377  return sl;
1378  }
1379 };
1380 
1382 {
1383  static Process::PortItemLayout layout() noexcept
1384  {
1385  return Process::DefaultControlLayouts::pad();
1386  }
1387 
1388  template <typename T, typename Control_T>
1389  static auto make_widget(
1390  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1391  QWidget* parent, QObject* context)
1392  {
1393  SCORE_TODO;
1394  return nullptr; // TODO
1395  }
1396 
1397  template <typename T, typename Control_T>
1398  static QGraphicsItem* make_item(
1399  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1400  QGraphicsItem* parent, QObject* context)
1401  {
1402  auto sl = new score::QGraphicsXYZChooser{nullptr};
1403  sl->setValue(ossia::convert<ossia::vec3f>(inlet.value()));
1404  bindVec3Domain(slider, inlet, *sl);
1405 
1406  QObject::connect(
1407  sl, &score::QGraphicsXYZChooser::sliderMoved, context, [=, &inlet, &ctx] {
1408  sl->moving = true;
1409  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
1410  });
1411  QObject::connect(
1412  sl, &score::QGraphicsXYZChooser::sliderReleased, context, [&ctx, sl]() {
1413  ctx.dispatcher.commit();
1414  sl->moving = false;
1415  });
1416 
1417  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1418  if(!sl->moving)
1419  sl->setValue(ossia::convert<ossia::vec3f>(val));
1420  });
1421 
1422  return sl;
1423  }
1424 };
1425 
1427 {
1428  static Process::PortItemLayout layout() noexcept
1429  {
1430  return Process::DefaultControlLayouts::pad();
1431  }
1432 
1433  template <typename T, typename Control_T>
1434  static auto make_widget(
1435  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1436  QWidget* parent, QObject* context)
1437  {
1438  SCORE_TODO;
1439  return nullptr; // TODO
1440  }
1441 
1442  static QGraphicsItem* make_item(
1443  const Process::XYSpinboxes& slider, Process::XYSpinboxes& inlet,
1444  const score::DocumentContext& ctx, QGraphicsItem* parent, QObject* context)
1445  {
1446  using Control_T = Process::XYSpinboxes;
1447  if(slider.integral)
1448  {
1449  auto sl = new score::QGraphicsIntXYSpinboxChooser{false, nullptr};
1450  bindVec2Domain(slider, inlet, *sl);
1451  sl->setValue(ossia::convert<ossia::vec2f>(inlet.value()));
1452 
1453  QObject::connect(
1454  sl, &score::QGraphicsIntXYSpinboxChooser::sliderMoved, context,
1455  [=, &inlet, &ctx] {
1456  sl->moving = true;
1457  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
1458  });
1459  QObject::connect(
1460  sl, &score::QGraphicsIntXYSpinboxChooser::sliderReleased, context,
1461  [&ctx, sl]() {
1462  ctx.dispatcher.commit();
1463  sl->moving = false;
1464  });
1465 
1466  QObject::connect(
1467  &inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1468  if(!sl->moving)
1469  sl->setValue(ossia::convert<ossia::vec2f>(val));
1470  });
1471 
1472  return sl;
1473  }
1474  else
1475  {
1476  auto sl = new score::QGraphicsXYSpinboxChooser{false, nullptr};
1477  bindVec2Domain(slider, inlet, *sl);
1478  sl->setValue(
1479  LinearNormalizer::to01(*sl, ossia::convert<ossia::vec2f>(inlet.value())));
1480 
1481  QObject::connect(
1482  sl, &score::QGraphicsXYSpinboxChooser::sliderMoved, context,
1483  [=, &inlet, &ctx] {
1484  sl->moving = true;
1485  ctx.dispatcher.submit<SetControlValue<Control_T>>(
1486  inlet, LinearNormalizer::from01(*sl, sl->value()));
1487  });
1488  QObject::connect(
1489  sl, &score::QGraphicsXYSpinboxChooser::sliderReleased, context, [&ctx, sl]() {
1490  ctx.dispatcher.commit();
1491  sl->moving = false;
1492  });
1493 
1494  QObject::connect(
1495  &inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1496  if(!sl->moving)
1497  sl->setValue(LinearNormalizer::to01(*sl, ossia::convert<ossia::vec2f>(val)));
1498  });
1499 
1500  return sl;
1501  }
1502  }
1503 };
1504 
1506 {
1507  static Process::PortItemLayout layout() noexcept
1508  {
1509  return Process::DefaultControlLayouts::pad();
1510  }
1511 
1512  template <typename T, typename Control_T>
1513  static auto make_widget(
1514  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1515  QWidget* parent, QObject* context)
1516  {
1517  SCORE_TODO;
1518  return nullptr; // TODO
1519  }
1520 
1521  template <typename T, typename Control_T>
1522  static QGraphicsItem* make_item(
1523  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1524  QGraphicsItem* parent, QObject* context)
1525  {
1526  auto sl = new score::QGraphicsXYZSpinboxChooser{nullptr};
1527  bindVec3Domain(slider, inlet, *sl);
1528  sl->setValue(
1529  LinearNormalizer::to01(*sl, ossia::convert<ossia::vec3f>(inlet.value())));
1530 
1531  QObject::connect(
1532  sl, &score::QGraphicsXYZSpinboxChooser::sliderMoved, context, [=, &inlet, &ctx] {
1533  sl->moving = true;
1534  ctx.dispatcher.submit<SetControlValue<Control_T>>(
1535  inlet, LinearNormalizer::from01(*sl, sl->value()));
1536  });
1537  QObject::connect(
1538  sl, &score::QGraphicsXYZSpinboxChooser::sliderReleased, context, [&ctx, sl]() {
1539  ctx.dispatcher.commit();
1540  sl->moving = false;
1541  });
1542 
1543  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1544  if(!sl->moving)
1545  sl->setValue(LinearNormalizer::to01(*sl, ossia::convert<ossia::vec3f>(val)));
1546  });
1547 
1548  return sl;
1549  }
1550 };
1551 
1553 {
1554  static Process::PortItemLayout layout() noexcept
1555  {
1556  return Process::DefaultControlLayouts::slider();
1557  }
1558 
1559  template <typename T, typename Control_T>
1560  static auto make_widget(
1561  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1562  QWidget* parent, QObject* context)
1563  {
1564  SCORE_TODO;
1565  return nullptr; // TODO
1566  }
1567 
1568  template <typename T, typename Control_T>
1569  static QGraphicsItem* make_item(
1570  const T& slider, Control_T& inlet, const score::DocumentContext& ctx,
1571  QGraphicsItem* parent, QObject* context)
1572  {
1573  auto sl = new score::QGraphicsMultiSlider{nullptr};
1574  sl->setValue(inlet.value());
1575  sl->setRange(inlet.domain());
1576 
1577  QObject::connect(
1578  sl, &score::QGraphicsMultiSlider::sliderMoved, context, [=, &inlet, &ctx] {
1579  sl->moving = true;
1580  ctx.dispatcher.submit<SetControlValue<Control_T>>(inlet, sl->value());
1581  });
1582  QObject::connect(
1583  sl, &score::QGraphicsMultiSlider::sliderReleased, context, [&ctx, sl]() {
1584  ctx.dispatcher.commit();
1585  sl->moving = false;
1586  });
1587 
1588  QObject::connect(&inlet, &Control_T::valueChanged, sl, [=](const ossia::value& val) {
1589  if(!sl->moving)
1590  sl->setValue(std::move(val));
1591  });
1592 
1593  return sl;
1594  }
1595 };
1596 
1598 using Bargraph = FloatDisplay;
1599 }
The CommandDispatcher class.
Definition: CommandDispatcher.hpp:13
void identified_object_destroying(IdentifiedObjectAbstract *o)
To be called by subclasses.
void submit(Args &&... args)
Definition: OngoingCommandDispatcher.hpp:37
void commit()
Definition: OngoingCommandDispatcher.hpp:61
Definition: score-lib-process/Process/Dataflow/Port.hpp:202
Definition: ScriptEditor.hpp:21
Definition: SetControlValue.hpp:34
Definition: SetControlValue.hpp:13
Definition: ComboBox.hpp:10
Definition: QGraphicsButton.hpp:16
Definition: QGraphicsCheckBox.hpp:16
Definition: QGraphicsCombo.hpp:18
Definition: QGraphicsEnum.hpp:17
Definition: QGraphicsHSVChooser.hpp:18
Definition: QGraphicsIntSlider.hpp:17
Definition: QGraphicsSpinbox.hpp:62
Definition: QGraphicsXYSpinbox.hpp:58
Definition: QGraphicsMultiSlider.hpp:24
Definition: QGraphicsPixmapEnum.hpp:17
Definition: QGraphicsRangeSlider.hpp:21
Definition: QGraphicsSpinbox.hpp:16
Definition: QGraphicsTextButton.hpp:16
Definition: QGraphicsTimeChooser.hpp:21
Definition: QGraphicsToggle.hpp:16
Definition: QGraphicsXYChooser.hpp:18
Definition: QGraphicsXYSpinbox.hpp:20
Definition: QGraphicsXYZChooser.hpp:19
Definition: QGraphicsXYZSpinbox.hpp:19
Base classes and tools to implement processes and layers.
Definition: JSONVisitor.hpp:1324
Utilities for OSSIA data structures.
Definition: DeviceInterface.hpp:33
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:44
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:59
Definition: score-lib-process/Process/Dataflow/Port.hpp:90
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:741
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:786
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1182
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1089
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1003
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:103
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:350
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:402
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:517
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1292
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:697
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:298
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:224
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:449
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:866
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1553
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:962
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:934
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:589
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1273
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:648
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1336
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1427
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1382
Definition: plugins/score-lib-process/Process/Dataflow/ControlWidgets.hpp:1506
Definition: DocumentContext.hpp:18
Definition: lib/score/widgets/ControlWidgets.hpp:13
Definition: lib/score/widgets/ControlWidgets.hpp:72
Definition: lib/score/widgets/ControlWidgets.hpp:29