Loading...
Searching...
No Matches
QmlObjects.hpp
1#pragma once
2#include <State/Domain.hpp>
3
4#include <Process/Dataflow/Port.hpp>
5#include <Process/Dataflow/WidgetInlets.hpp>
6
7#include <JS/Qml/QtMetatypes.hpp>
8
9#if defined(SCORE_HAS_GPU_JS)
10#include <Gfx/TexturePort.hpp>
11
12#include <QQuickItem>
13#endif
14
15#include <score/tools/Debug.hpp>
16
17#include <ossia/detail/math.hpp>
18#include <ossia/detail/ssize.hpp>
19#include <ossia/network/domain/domain.hpp>
20#include <ossia-qt/js_utilities.hpp>
21
22#include <QJSValue>
23#include <QObject>
24#include <QQmlListProperty>
25#include <QVariant>
26#include <QVector>
27
28#include <libremidi/message.hpp>
29
30#include <score_plugin_js_export.h>
31#include <wobjectimpl.h>
32
33#include <verdigris>
34
35class QQuickItem;
36namespace JS
37{
38class SCORE_PLUGIN_JS_EXPORT Inlet : public QObject
39{
40 W_OBJECT(Inlet)
41
42public:
43 using QObject::QObject;
44 virtual ~Inlet() override;
45 virtual Process::Inlet* make(Id<Process::Port>&& id, QObject*) = 0;
46 virtual bool isEvent() const { return false; }
47
48 W_INLINE_PROPERTY_CREF(QString, address, {}, address, setAddress, addressChanged)
49};
50
51class SCORE_PLUGIN_JS_EXPORT Outlet : public QObject
52{
53 W_OBJECT(Outlet)
54
55public:
56 using QObject::QObject;
57 virtual ~Outlet() override;
58 virtual Process::Outlet* make(Id<Process::Port>&& id, QObject*) = 0;
59
60 W_INLINE_PROPERTY_CREF(QString, address, {}, address, setAddress, addressChanged)
61};
62
63struct SCORE_PLUGIN_JS_EXPORT InValueMessage
64{
65 W_GADGET(InValueMessage)
66
67public:
68 qreal timestamp;
69 QVariant value;
70 W_PROPERTY(qreal, timestamp MEMBER timestamp)
71 W_PROPERTY(QVariant, value MEMBER value)
72};
73
74struct SCORE_PLUGIN_JS_EXPORT OutValueMessage
75{
76 W_GADGET(OutValueMessage)
77
78public:
79 qreal timestamp;
80 QJSValue value;
81 W_PROPERTY(qreal, timestamp MEMBER timestamp)
82 W_PROPERTY(QJSValue, value MEMBER value)
83};
84
85class SCORE_PLUGIN_JS_EXPORT ValueInlet : public Inlet
86{
87 W_OBJECT(ValueInlet)
88
89 QVariant m_value;
90 QVariantList m_values;
91
92public:
93 explicit ValueInlet(QObject* parent = nullptr);
94 virtual ~ValueInlet() override;
95 QVariant value() const;
96 QVariantList values() const { return m_values; }
97
98 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
99 {
100 return new Process::ValueInlet(id, parent);
101 }
102
103 int length() const noexcept;
104 W_SLOT(length)
105
106 QVariant at(int index) const noexcept;
107 W_SLOT(at)
108
109 void clear() { m_values.clear(); }
110 void setValue(QVariant value);
111 void addValue(QVariant&& val) { m_values.append(std::move(val)); }
112 void valueChanged(QVariant value) W_SIGNAL(valueChanged, value);
113
114 W_PROPERTY(QVariantList, values READ values)
115 W_PROPERTY(QVariant, value READ value NOTIFY valueChanged)
116};
117
118class SCORE_PLUGIN_JS_EXPORT ControlInlet : public Inlet
119{
120 W_OBJECT(ControlInlet)
121
122 QVariant m_value;
123
124public:
125 explicit ControlInlet(QObject* parent = nullptr);
126 virtual ~ControlInlet() override;
127 QVariant value() const noexcept;
128
129 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
130 {
131 return new Process::ControlInlet(id, parent);
132 }
133
134 void clear() { m_value = QVariant{}; }
135 virtual void setValue(QVariant value);
136 void valueChanged(QVariant value) W_SIGNAL(valueChanged, value);
137
138 W_PROPERTY(QVariant, value READ value NOTIFY valueChanged)
139};
140
141template <typename Impl, typename ValueType>
142class SCORE_PLUGIN_JS_EXPORT GenericControlInlet : public ControlInlet
143{
144 W_OBJECT(GenericControlInlet)
145
146public:
147 using ControlInlet::ControlInlet;
148 virtual ~GenericControlInlet() override = default;
149 bool isEvent() const override { return true; }
150 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
151 {
152 return new Impl(id, parent);
153 }
154
155 void clear() { m_value = {}; }
156 ValueType value() const noexcept { return m_value; }
157 void setValue(QVariant value) override
158 {
159 auto conv = value.value<ValueType>();
160 if(m_value == conv)
161 return;
162
163 m_value = std::move(conv);
164 valueChanged(m_value);
165 }
166 void setValue(ValueType value)
167 {
168 if(m_value == value)
169 return;
170
171 m_value = value;
172 valueChanged(m_value);
173 }
174 void valueChanged(ValueType value) W_SIGNAL(valueChanged, value);
175
176 W_PROPERTY(ValueType, value READ value NOTIFY valueChanged)
177
178private:
179 ValueType m_value{};
180};
181W_OBJECT_IMPL((GenericControlInlet<A, B>), template <typename A, typename B>)
182struct SCORE_PLUGIN_JS_EXPORT FloatRangeSpinBox
184{
185 W_OBJECT(FloatRangeSpinBox);
186 using GenericControlInlet::GenericControlInlet;
187};
188struct SCORE_PLUGIN_JS_EXPORT IntRangeSlider
189 : JS::GenericControlInlet<Process::IntRangeSlider, QVector2D>
190{
191 W_OBJECT(IntRangeSlider);
192 using GenericControlInlet::GenericControlInlet;
193};
194struct SCORE_PLUGIN_JS_EXPORT IntRangeSpinBox
195 : JS::GenericControlInlet<Process::IntRangeSpinBox, QVector2D>
196{
197 W_OBJECT(IntRangeSpinBox);
198 using GenericControlInlet::GenericControlInlet;
199};
200struct SCORE_PLUGIN_JS_EXPORT HSVSlider
201 : JS::GenericControlInlet<Process::HSVSlider, QVector4D>
202{
203 W_OBJECT(HSVSlider);
204 using GenericControlInlet::GenericControlInlet;
205};
206struct SCORE_PLUGIN_JS_EXPORT XYSlider
207 : JS::GenericControlInlet<Process::XYSlider, QVector2D>
208{
209 W_OBJECT(XYSlider);
210 using GenericControlInlet::GenericControlInlet;
211};
212struct SCORE_PLUGIN_JS_EXPORT XYZSlider
213 : JS::GenericControlInlet<Process::XYZSlider, QVector3D>
214{
215 W_OBJECT(XYZSlider);
216 using GenericControlInlet::GenericControlInlet;
217};
218struct SCORE_PLUGIN_JS_EXPORT XYSpinboxes
219 : JS::GenericControlInlet<Process::XYSpinboxes, QVector2D>
220{
221 W_OBJECT(XYSpinboxes);
222 using GenericControlInlet::GenericControlInlet;
223};
224struct SCORE_PLUGIN_JS_EXPORT XYZSpinboxes
225 : JS::GenericControlInlet<Process::XYZSpinboxes, QVector3D>
226{
227 W_OBJECT(XYZSpinboxes);
228 using GenericControlInlet::GenericControlInlet;
229};
230struct SCORE_PLUGIN_JS_EXPORT MultiSlider
231 : JS::GenericControlInlet<Process::MultiSlider, QVector<qreal>>
232{
233 W_OBJECT(MultiSlider);
234 using GenericControlInlet::GenericControlInlet;
235};
236struct SCORE_PLUGIN_JS_EXPORT FileChooser
237 : JS::GenericControlInlet<Process::FileChooser, QString>
238{
239 W_OBJECT(FileChooser);
240 using GenericControlInlet::GenericControlInlet;
241};
242struct SCORE_PLUGIN_JS_EXPORT AudioFileChooser
243 : JS::GenericControlInlet<Process::AudioFileChooser, QString>
244{
245 W_OBJECT(AudioFileChooser);
246 using GenericControlInlet::GenericControlInlet;
247};
248struct SCORE_PLUGIN_JS_EXPORT VideoFileChooser
249 : JS::GenericControlInlet<Process::VideoFileChooser, QString>
250{
251 W_OBJECT(VideoFileChooser);
252 using GenericControlInlet::GenericControlInlet;
253};
254
255template <typename Impl = Process::FloatSlider>
256class SCORE_PLUGIN_JS_EXPORT FloatSlider : public GenericControlInlet<Impl, float>
257{
258 W_OBJECT(FloatSlider)
259
260public:
261 using GenericControlInlet<Impl, float>::GenericControlInlet;
262 virtual ~FloatSlider() override = default;
263 bool isEvent() const override { return true; }
264
265 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
266 {
267 return new Impl{(float)m_min, (float)m_max, (float)m_init,
268 this->objectName(), id, parent};
269 }
270
271 W_INLINE_PROPERTY_VALUE(qreal, init, {0.5}, init, setInit, initChanged)
272 W_INLINE_PROPERTY_VALUE(qreal, min, {0.}, getMin, setMin, minChanged)
273 W_INLINE_PROPERTY_VALUE(qreal, max, {1.}, getMax, setMax, maxChanged)
274};
275W_OBJECT_IMPL(JS::FloatSlider<Impl>, template <typename Impl>)
276
277template <typename Impl = Process::IntSlider>
278class SCORE_PLUGIN_JS_EXPORT IntSlider : public GenericControlInlet<Impl, int>
279{
280 W_OBJECT(IntSlider)
281
282public:
283 using GenericControlInlet<Impl, int>::GenericControlInlet;
284 virtual ~IntSlider() override = default;
285 bool isEvent() const override { return true; }
286
287 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
288 {
289 return new Impl{m_min, m_max, m_init, this->objectName(), id, parent};
290 }
291
292 W_INLINE_PROPERTY_VALUE(int, init, {0}, init, setInit, initChanged)
293 W_INLINE_PROPERTY_VALUE(int, min, {0}, getMin, setMin, minChanged)
294 W_INLINE_PROPERTY_VALUE(int, max, {127}, getMax, setMax, maxChanged)
295};
296W_OBJECT_IMPL(JS::IntSlider<Impl>, template <typename Impl>)
297
298class SCORE_PLUGIN_JS_EXPORT Enum : public ControlInlet
299{
300 W_OBJECT(Enum)
301
302public:
303 using ControlInlet::ControlInlet;
304 virtual ~Enum() override;
305 bool isEvent() const override { return true; }
306
307 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
308 {
309 return new Process::Enum{m_choices, {}, current(), objectName(), id, parent};
310 }
311
312 auto getValues() const { return choices(); }
313
314 std::string current() const
315 {
316 if(!m_choices.isEmpty() && ossia::valid_index(m_index, m_choices))
317 {
318 return m_choices[m_index].toStdString();
319 }
320 return {};
321 }
322
323 W_INLINE_PROPERTY_VALUE(int, index, {}, index, setIndex, indexChanged)
324 W_INLINE_PROPERTY_CREF(QStringList, choices, {}, choices, setChoices, choicesChanged)
325};
326
327class SCORE_PLUGIN_JS_EXPORT Toggle : public ControlInlet
328{
329 W_OBJECT(Toggle)
330
331public:
332 using ControlInlet::ControlInlet;
333 virtual ~Toggle() override;
334 bool isEvent() const override { return true; }
335 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
336 {
337 return new Process::Toggle{m_checked, objectName(), id, parent};
338 }
339
340 W_INLINE_PROPERTY_VALUE(bool, checked, {}, checked, setChecked, checkedChanged)
341};
342
343class SCORE_PLUGIN_JS_EXPORT Button : public ControlInlet
344{
345 W_OBJECT(Button)
346
347public:
348 using ControlInlet::ControlInlet;
349 virtual ~Button() override;
350 bool isEvent() const override { return true; }
351 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
352 {
353 return new Process::Button{objectName(), id, parent};
354 }
355
356 W_INLINE_PROPERTY_VALUE(bool, checked, {}, checked, setChecked, checkedChanged)
357};
358
359class SCORE_PLUGIN_JS_EXPORT Impulse : public ControlInlet
360{
361 W_OBJECT(Impulse)
362
363public:
364 using ControlInlet::ControlInlet;
365 virtual ~Impulse() override;
366 bool isEvent() const override { return false; }
367 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
368 {
369 return new Process::ImpulseButton{objectName(), id, parent};
370 }
371
372 void impulse() W_SIGNAL(impulse);
373};
374
375class SCORE_PLUGIN_JS_EXPORT LineEdit : public ControlInlet
376{
377 W_OBJECT(LineEdit)
378
379public:
380 using ControlInlet::ControlInlet;
381 virtual ~LineEdit() override;
382 bool isEvent() const override { return true; }
383 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
384 {
385 return new Process::LineEdit{m_text, objectName(), id, parent};
386 }
387
388 W_INLINE_PROPERTY_CREF(QString, text, {}, text, setText, textChanged)
389};
390
391class SCORE_PLUGIN_JS_EXPORT ValueOutlet : public Outlet
392{
393 W_OBJECT(ValueOutlet)
394
395 QJSValue m_value;
396
397public:
398 std::vector<OutValueMessage> values;
399
400 explicit ValueOutlet(QObject* parent = nullptr);
401 virtual ~ValueOutlet() override;
402 const QJSValue& value() const;
403 void clear()
404 {
405 m_value = QJSValue{};
406 values.clear();
407 }
408 Process::Outlet* make(Id<Process::Port>&& id, QObject* parent) override
409 {
410 return new Process::ValueOutlet(id, parent);
411 }
412
413public:
414 void setValue(const QJSValue& value);
415 W_SLOT(setValue);
416 void addValue(qreal timestamp, QJSValue t);
417 W_SLOT(addValue);
418
419 W_PROPERTY(QJSValue, value READ value WRITE setValue)
420};
421
422class SCORE_PLUGIN_JS_EXPORT AudioInlet : public Inlet
423{
424 W_OBJECT(AudioInlet)
425
426public:
427 explicit AudioInlet(QObject* parent = nullptr);
428 virtual ~AudioInlet() override;
429 const QVector<QVector<double>>& audio() const;
430 void setAudio(const QVector<QVector<double>>& audio);
431
432 QVector<double> channel(int i) const
433 {
434 if(m_audio.size() > i)
435 return m_audio[i];
436 return {};
437 }
438 W_INVOKABLE(channel);
439
440 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
441 {
442 return new Process::AudioInlet(id, parent);
443 }
444
445private:
446 QVector<QVector<double>> m_audio;
447};
448
449class SCORE_PLUGIN_JS_EXPORT AudioOutlet : public Outlet
450{
451 W_OBJECT(AudioOutlet)
452
453public:
454 explicit AudioOutlet(QObject* parent = nullptr);
455 virtual ~AudioOutlet() override;
456 Process::Outlet* make(Id<Process::Port>&& id, QObject* parent) override
457 {
458 auto p = new Process::AudioOutlet(id, parent);
459 if(id.val() == 0)
460 p->setPropagate(true);
461 return p;
462 }
463
464 const QVector<QVector<double>>& audio() const;
465
466 void setChannel(int i, const QJSValue& v);
467 W_INVOKABLE(setChannel)
468private:
469 QVector<QVector<double>> m_audio;
470};
471
472class SCORE_PLUGIN_JS_EXPORT MidiMessage
473{
474 W_GADGET(MidiMessage)
475
476public:
477 QByteArray bytes;
478
479 W_PROPERTY(QByteArray, bytes MEMBER bytes)
480};
481
482class SCORE_PLUGIN_JS_EXPORT MidiInlet : public Inlet
483{
484 W_OBJECT(MidiInlet)
485
486public:
487 explicit MidiInlet(QObject* parent = nullptr);
488 virtual ~MidiInlet() override;
489 template <typename T>
490 void setMidi(const T& arr)
491 {
492 m_midi.clear();
493 for(const libremidi::message& mess : arr)
494 {
495 const auto N = mess.size();
496 QVector<int> m;
497 m.resize(N);
498
499 for(std::size_t i = 0; i < N; i++)
500 m[i] = mess.bytes[i];
501
502 m_midi.push_back(QVariant::fromValue(m));
503 }
504 }
505
506 QVariantList messages() const { return m_midi; }
507 W_INVOKABLE(messages);
508
509 Process::Inlet* make(Id<Process::Port>&& id, QObject* parent) override
510 {
511 return new Process::MidiInlet(id, parent);
512 }
513
514private:
515 QVariantList m_midi;
516};
517
518class SCORE_PLUGIN_JS_EXPORT MidiOutlet : public Outlet
519{
520 W_OBJECT(MidiOutlet)
521
522public:
523 explicit MidiOutlet(QObject* parent = nullptr);
524 virtual ~MidiOutlet() override;
525 Process::Outlet* make(Id<Process::Port>&& id, QObject* parent) override
526 {
527 return new Process::MidiOutlet(id, parent);
528 }
529
530 void clear();
531 const QVector<QVector<int>>& midi() const;
532
533 void setMessages(const QVariantList m)
534 {
535 m_midi.clear();
536 for(auto& v : m)
537 {
538 if(v.canConvert<QVector<int>>())
539 m_midi.push_back(v.value<QVector<int>>());
540 }
541 }
542 W_INVOKABLE(setMessages);
543
544 void add(QVector<int> m) { m_midi.push_back(std::move(m)); }
545 W_INVOKABLE(add);
546
547private:
548 QVector<QVector<int>> m_midi;
549};
550
551#if defined(SCORE_HAS_GPU_JS)
552class TextureOutlet : public Outlet
553{
554 W_OBJECT(TextureOutlet)
555
556public:
557 explicit TextureOutlet(QObject* parent = nullptr);
558 virtual ~TextureOutlet() override;
559 Process::Outlet* make(Id<Process::Port>&& id, QObject* parent) override
560 {
561 auto p = new Gfx::TextureOutlet(id, parent);
562 return p;
563 }
564
565 QQuickItem* item() /*Qt6: const*/ noexcept { return m_item; }
566 void setItem(QQuickItem* v) { m_item = v; }
567
568 W_PROPERTY(QQuickItem*, item READ item WRITE setItem CONSTANT)
569private:
570 QQuickItem* m_item{};
571};
572#endif
573
574class Script : public QObject
575{
576 W_OBJECT(Script)
577 W_CLASSINFO("DefaultProperty", "data")
578 W_CLASSINFO(
579 "qt_QmlJSWrapperFactoryMethod", "_q_createJSWrapper(QV4::ExecutionEngine*)")
580
581public:
582 QQmlListProperty<QObject> data() noexcept { return {this, &m_data}; }
583
584 QJSValue& tick() /*Qt6: const*/ noexcept { return m_tick; }
585 void setTick(const QJSValue& v) { m_tick = v; }
586 QJSValue& start() /*Qt6: const*/ noexcept { return m_start; }
587 void setStart(const QJSValue& v) { m_start = v; }
588 QJSValue& stop() /*Qt6: const*/ noexcept { return m_stop; }
589 void setStop(const QJSValue& v) { m_stop = v; }
590 QJSValue& pause() /*Qt6: const*/ noexcept { return m_pause; }
591 void setPause(const QJSValue& v) { m_pause = v; }
592 QJSValue& resume() /*Qt6: const*/ noexcept { return m_resume; }
593 void setResume(const QJSValue& v) { m_resume = v; }
594 W_PROPERTY(QJSValue, tick READ tick WRITE setTick CONSTANT)
595 W_PROPERTY(QJSValue, start READ start WRITE setStart CONSTANT)
596 W_PROPERTY(QJSValue, stop READ stop WRITE setStop CONSTANT)
597 W_PROPERTY(QJSValue, pause READ pause WRITE setPause CONSTANT)
598 W_PROPERTY(QJSValue, resume READ resume WRITE setResume CONSTANT)
599 W_PROPERTY(QQmlListProperty<QObject>, data READ data)
600
601private:
602 QList<QObject*> m_data;
603 QJSValue m_tick;
604 QJSValue m_start;
605 QJSValue m_stop;
606 QJSValue m_pause;
607 QJSValue m_resume;
608};
609}
610
611inline QDataStream& operator<<(QDataStream& i, const JS::MidiMessage& sel)
612{
613 SCORE_ABORT;
614 return i;
615}
616inline QDataStream& operator>>(QDataStream& i, JS::MidiMessage& sel)
617{
618 SCORE_ABORT;
619 return i;
620}
621inline QDataStream& operator<<(QDataStream& i, const JS::InValueMessage& sel)
622{
623 SCORE_ABORT;
624 return i;
625}
626inline QDataStream& operator>>(QDataStream& i, JS::InValueMessage& sel)
627{
628 SCORE_ABORT;
629 return i;
630}
631inline QDataStream& operator<<(QDataStream& i, const JS::OutValueMessage& sel)
632{
633 SCORE_ABORT;
634 return i;
635}
636inline QDataStream& operator>>(QDataStream& i, JS::OutValueMessage& sel)
637{
638 SCORE_ABORT;
639 return i;
640}
641Q_DECLARE_METATYPE(JS::ValueInlet*)
642Q_DECLARE_METATYPE(JS::ValueOutlet*)
643Q_DECLARE_METATYPE(JS::AudioInlet*)
644Q_DECLARE_METATYPE(JS::AudioOutlet*)
645Q_DECLARE_METATYPE(JS::MidiMessage)
646Q_DECLARE_METATYPE(JS::MidiInlet*)
647Q_DECLARE_METATYPE(JS::MidiOutlet*)
648
649W_REGISTER_ARGTYPE(JS::ValueInlet*)
650W_REGISTER_ARGTYPE(JS::ValueOutlet*)
651W_REGISTER_ARGTYPE(JS::AudioInlet*)
652W_REGISTER_ARGTYPE(JS::AudioOutlet*)
653W_REGISTER_ARGTYPE(JS::MidiMessage)
654W_REGISTER_ARGTYPE(JS::MidiInlet*)
655W_REGISTER_ARGTYPE(JS::MidiOutlet*)
Definition QmlObjects.hpp:423
Definition QmlObjects.hpp:450
Definition QmlObjects.hpp:344
Definition QmlObjects.hpp:119
Definition QmlObjects.hpp:299
Definition QmlObjects.hpp:257
Definition QmlObjects.hpp:143
Definition QmlObjects.hpp:360
Definition QmlObjects.hpp:39
Definition QmlObjects.hpp:279
Definition QmlObjects.hpp:376
Definition QmlObjects.hpp:483
Definition QmlObjects.hpp:473
Definition QmlObjects.hpp:519
Definition QmlObjects.hpp:52
Definition QmlObjects.hpp:575
Definition QmlObjects.hpp:328
Definition QmlObjects.hpp:86
Definition QmlObjects.hpp:392
Definition Port.hpp:300
Definition Port.hpp:323
Definition Port.hpp:203
Definition Port.hpp:177
Definition Port.hpp:379
Definition Port.hpp:402
Definition Port.hpp:273
Definition Port.hpp:492
Definition Port.hpp:515
The id_base_t class.
Definition Identifier.hpp:57
Base classes and tools to implement processes and layers.
Definition JSONVisitor.hpp:1324
Definition QmlObjects.hpp:244
Definition QmlObjects.hpp:238
Definition QmlObjects.hpp:184
Definition QmlObjects.hpp:202
Definition QmlObjects.hpp:64
Definition QmlObjects.hpp:190
Definition QmlObjects.hpp:196
Definition QmlObjects.hpp:232
Definition QmlObjects.hpp:75
Definition QmlObjects.hpp:250
Definition QmlObjects.hpp:208
Definition QmlObjects.hpp:220
Definition QmlObjects.hpp:214
Definition QmlObjects.hpp:226