Loading...
Searching...
No Matches
CPUNode.hpp
1#pragma once
2
3#include <JS/Executor/JSAPIWrapper.hpp>
4#include <JS/JSProcessMetadata.hpp>
5#include <JS/Qml/Metatypes.hpp>
6#include <JS/Qml/QmlObjects.hpp>
7#include <JS/Qml/ValueTypes.Qt6.hpp>
8
9#include <ossia/dataflow/graph/graph_interface.hpp>
10#include <ossia/dataflow/graph_edge.hpp>
11#include <ossia/dataflow/graph_edge_helpers.hpp>
12#include <ossia/dataflow/graph_node.hpp>
13#include <ossia/dataflow/node_process.hpp>
14#include <ossia/dataflow/port.hpp>
15#include <ossia/detail/logger.hpp>
16#include <ossia/detail/ssize.hpp>
17#include <ossia/editor/scenario/time_interval.hpp>
18#include <ossia/editor/state/message.hpp>
19#include <ossia/editor/state/state.hpp>
20
21#include <ossia-qt/invoke.hpp>
22#include <ossia-qt/js_utilities.hpp>
23#include <ossia-qt/time.hpp>
24#include <ossia-qt/token_request.hpp>
25#include <JS/Qml/VariantToJs.hpp>
26namespace ossia::qt
27{
28class qml_engine_functions;
29}
30
31namespace LocalTree
32{
33struct ScriptableSnapshot;
34}
35namespace JS
36{
37class SCORE_PLUGIN_JS_EXPORT js_node final : public ossia::graph_node
38{
39public:
40 js_node(
41 ossia::execution_state& st,
42 std::shared_ptr<const LocalTree::ScriptableSnapshot> names);
43 ~js_node();
44
45 [[nodiscard]] std::string label() const noexcept override { return "javascript"; }
46
47 void run(const ossia::token_request& t, ossia::exec_state_facade) noexcept override;
48 void clear() noexcept override;
49 void setupComponent();
50 void setScript(const QString& rootPath, const QString& val);
51
52 ossia::execution_state& m_st;
53
54 std::shared_ptr<QQmlEngine> m_engine{};
55 QQmlContext* m_context{};
56 std::vector<Inlet*> m_jsInlets;
57 std::vector<std::pair<ControlInlet*, ossia::inlet_ptr>> m_ctrlInlets;
58 std::vector<std::pair<Impulse*, ossia::inlet_ptr>> m_impulseInlets;
59 std::vector<std::pair<ValueInlet*, ossia::inlet_ptr>> m_valInlets;
60 std::vector<std::pair<ValueOutlet*, ossia::outlet_ptr>> m_valOutlets;
61 std::vector<std::pair<AudioInlet*, ossia::inlet_ptr>> m_audInlets;
62 std::vector<std::pair<AudioOutlet*, ossia::outlet_ptr>> m_audOutlets;
63 std::vector<std::pair<MidiInlet*, ossia::inlet_ptr>> m_midInlets;
64 std::vector<std::pair<MidiOutlet*, ossia::outlet_ptr>> m_midOutlets;
65 JS::Script* m_object{};
66 ossia::qt::qml_engine_functions* m_execFuncs{};
68 std::shared_ptr<const LocalTree::ScriptableSnapshot> m_names;
70 bool m_namesChanged{};
72 QJSValue m_namespaces;
73 std::optional<QJSValueList> m_tickCall;
74 QPointer<QObject> m_uiContext;
75 QPointer<JS::ProcessModel> m_modelContext;
76 std::function<void(QVariant)> m_messageToUi;
77 std::size_t m_gcIndex{};
78
79 JS::JSState m_modelState;
80
81 bool triggerStart{};
82 bool triggerStop{};
83 bool triggerPause{};
84 bool triggerResume{};
85
86 void setControl(std::size_t index, const QVariant& val)
87 {
88 if(index >= m_jsInlets.size())
89 return;
90 if(auto v = qobject_cast<ValueInlet*>(m_jsInlets[index]))
91 v->setValue(val);
92 else if(auto v = qobject_cast<ControlInlet*>(m_jsInlets[index]))
93 v->setValue(val);
94 }
95 void impulse(std::size_t index)
96 {
97 if(index >= m_jsInlets.size())
98 return;
99 if(auto v = qobject_cast<Impulse*>(m_jsInlets[index]))
100 v->impulse();
101 }
102
103 void uiMessage(const QVariant& v)
104 {
105 if(!m_object)
106 return;
107
108 const auto& on_ui = this->m_object->uiEvent();
109 if(!on_ui.isCallable())
110 return;
111
112 on_ui.call({JS::variantToJs(*m_engine, v)});
113 }
114
115 void stateElementChanged(const QString& k, const ossia::value& v)
116 {
117 if(!m_object)
118 return;
119
120 const auto& on_stateUpdated = this->m_object->stateUpdated();
121 if(!on_stateUpdated.isCallable())
122 return;
123
124 if(v.valid())
125 {
126 if(auto res = v.apply(ossia::qt::ossia_to_qvariant{}); res.isValid())
127 on_stateUpdated.call({k, JS::variantToJs(*m_engine, res)});
128 else
129 on_stateUpdated.call({k, QJSValue{}});
130 }
131 else
132 on_stateUpdated.call({k, QJSValue{}});
133 }
134};
135
136struct js_process final : public ossia::node_process
137{
138 using node_process::node_process;
139 js_node& js() const { return static_cast<js_node&>(*node); }
140 void start() override { js().triggerStart = true; }
141 void stop() override { js().triggerStop = true; }
142 void pause() override { js().triggerPause = true; }
143 void resume() override { js().triggerResume = true; }
144 void transport_impl(ossia::time_value date) override
145 {
146 QMetaObject::invokeMethod(
147 js().m_object, "transport", Qt::DirectConnection,
148 Q_ARG(QVariant, double(date.impl)));
149 }
150 void offset_impl(ossia::time_value date) override
151 {
152 QMetaObject::invokeMethod(
153 js().m_object, "offset", Qt::DirectConnection,
154 Q_ARG(QVariant, double(date.impl)));
155 }
156};
157
158}
Definition QmlObjects.hpp:849
Definition CPUNode.hpp:38
std::shared_ptr< const LocalTree::ScriptableSnapshot > m_names
Replaced from the GUI thread through the execution queue.
Definition CPUNode.hpp:68
QJSValue m_namespaces
Score.Controls, Triggers and Conditions of this process.
Definition CPUNode.hpp:72
Local tree provides a way to extend the tree given through the Engine::Network::LocalDevice.
Definition BaseCallbackWrapper.hpp:9
Definition CPUNode.hpp:137