Skip to content

Commit 1f9b3f6

Browse files
committed
js: start work for showing 3D uis
1 parent 20ccccf commit 1f9b3f6

File tree

2 files changed

+195
-2
lines changed

2 files changed

+195
-2
lines changed

src/plugins/score-plugin-js/JS/JSProcessModel.cpp

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <QFileInfo>
2828
#include <QFileSystemWatcher>
2929
#include <QQmlComponent>
30+
#include <QQuickWindow>
3031

3132
#include <wobjectimpl.h>
3233

@@ -76,6 +77,76 @@ Script {
7677
{
7778
setScript(data);
7879
}
80+
81+
setUiScript(R"_(import QtQuick
82+
import QtQuick3D
83+
84+
View3D {
85+
id: view
86+
anchors.fill: parent
87+
88+
//! [environment]
89+
environment: SceneEnvironment {
90+
clearColor: "skyblue"
91+
backgroundMode: SceneEnvironment.Color
92+
}
93+
//! [environment]
94+
95+
//! [camera]
96+
PerspectiveCamera {
97+
position: Qt.vector3d(0, 200, 300)
98+
eulerRotation.x: -30
99+
}
100+
//! [camera]
101+
102+
//! [light]
103+
DirectionalLight {
104+
eulerRotation.x: -30
105+
eulerRotation.y: -70
106+
}
107+
//! [light]
108+
109+
//! [objects]
110+
Model {
111+
position: Qt.vector3d(0, -200, 0)
112+
source: "#Cylinder"
113+
scale: Qt.vector3d(2, 0.2, 1)
114+
materials: [ DefaultMaterial {
115+
diffuseColor: "red"
116+
}
117+
]
118+
}
119+
120+
Model {
121+
position: Qt.vector3d(0, 150, 0)
122+
source: "#Sphere"
123+
124+
materials: [ DefaultMaterial {
125+
diffuseColor: "blue"
126+
}
127+
]
128+
129+
//! [animation]
130+
SequentialAnimation on y {
131+
loops: Animation.Infinite
132+
NumberAnimation {
133+
duration: 3000
134+
to: -150
135+
from: 150
136+
easing.type:Easing.InQuad
137+
}
138+
NumberAnimation {
139+
duration: 3000
140+
to: 150
141+
from: -150
142+
easing.type:Easing.OutQuad
143+
}
144+
}
145+
//! [animation]
146+
}
147+
//! [objects]
148+
}
149+
)_");
79150
metadata().setInstanceName(*this);
80151
}
81152

@@ -100,11 +171,49 @@ bool ProcessModel::validate(const QString& script) const noexcept
100171
}
101172
}
102173

174+
[[nodiscard]] Process::ScriptChangeResult
175+
ProcessModel::setUiScript(const QString& script)
176+
{
177+
Process::ScriptChangeResult res;
178+
const auto trimmed = script.trimmed();
179+
const QByteArray data = trimmed.toUtf8();
180+
181+
if(res = setUiQmlData(data); !res.valid)
182+
return res;
183+
184+
m_ui_script = script;
185+
uiScriptChanged(script);
186+
res.valid = true;
187+
return res;
188+
}
189+
103190
QString ProcessModel::effect() const noexcept
104191
{
105192
return m_qmlData;
106193
}
107194

195+
Process::ScriptChangeResult ProcessModel::setUiQmlData(const QByteArray& data)
196+
{
197+
Process::ScriptChangeResult res;
198+
if(!data.contains("import QtQuick"))
199+
return res;
200+
201+
auto script = m_cache.getUi(*this, data);
202+
if(!script)
203+
return res;
204+
205+
m_ui_qmlData = data;
206+
res.valid = true;
207+
// FIXME signal?
208+
209+
auto win = new QQuickWindow;
210+
win->setWidth(640);
211+
win->setHeight(640);
212+
script->setParentItem(win->contentItem());
213+
win->show();
214+
return res;
215+
}
216+
108217
[[nodiscard]] Process::ScriptChangeResult ProcessModel::setScript(const QString& script)
109218
{
110219
Process::ScriptChangeResult res;
@@ -132,7 +241,7 @@ QString ProcessModel::effect() const noexcept
132241
Process::ScriptChangeResult ProcessModel::setQmlData(const QByteArray& data, bool isFile)
133242
{
134243
Process::ScriptChangeResult res;
135-
if(!isFile && !data.startsWith("import"))
244+
if(!isFile && !data.contains("import "))
136245
return res;
137246

138247
auto script = m_cache.get(*this, data, isFile);
@@ -199,6 +308,11 @@ Script* ProcessModel::currentObject() const noexcept
199308
return m_cache.tryGet(m_qmlData, m_isFile);
200309
}
201310

311+
QQuickItem* ProcessModel::currentUI() const noexcept
312+
{
313+
return m_cache.tryGet(m_ui_qmlData);
314+
}
315+
202316
bool ProcessModel::isGpu() const noexcept
203317
{
204318
#if defined(SCORE_HAS_GPU_JS)
@@ -238,6 +352,19 @@ Script* ComponentCache::tryGet(const QByteArray& str, bool isFile) const noexcep
238352
}
239353
}
240354

355+
QQuickItem* ComponentCache::tryGet(const QByteArray& str) const noexcept
356+
{
357+
auto it = ossia::find_if(m_map, [&](const auto& k) { return k.key == str; });
358+
if(it != m_map.end())
359+
{
360+
return it->item.get();
361+
}
362+
else
363+
{
364+
return nullptr;
365+
}
366+
}
367+
241368
static std::once_flag qml_dummy_engine_setup{};
242369
Script* ComponentCache::get(
243370
const ProcessModel& process, const QByteArray& str, bool isFile) noexcept
@@ -312,6 +439,58 @@ Script* ComponentCache::get(
312439
}
313440
}
314441
}
442+
QQuickItem*
443+
ComponentCache::getUi(const ProcessModel& process, const QByteArray& str) noexcept
444+
{
445+
auto it = ossia::find_if(m_map, [&](const auto& k) { return k.key == str; });
446+
if(it != m_map.end())
447+
{
448+
return it->item.get();
449+
}
450+
else
451+
{
452+
static QQmlEngine dummyEngine;
453+
std::call_once(qml_dummy_engine_setup, [] { setupEngineImportPaths(dummyEngine); });
454+
455+
auto comp = std::make_unique<QQmlComponent>(&dummyEngine);
456+
{
457+
auto& lib = score::AppContext().settings<Library::Settings::Model>();
458+
// FIXME QTBUG-107204
459+
QString path = lib.getDefaultLibraryPath() + QDir::separator() + "Scripts"
460+
+ QDir::separator() + "include" + QDir::separator() + "Script.qml";
461+
comp->setData(str, QUrl::fromLocalFile(path));
462+
}
463+
const auto& errs = comp->errors();
464+
if(!errs.empty())
465+
{
466+
const auto& err = errs.first();
467+
qDebug() << err.line() << err.toString();
468+
auto str = err.toString();
469+
str.remove("<Unknown File>:");
470+
process.errorMessage(err.line(), str);
471+
return nullptr;
472+
}
473+
474+
auto obj = comp->create();
475+
auto script = qobject_cast<QQuickItem*>(obj);
476+
if(script)
477+
{
478+
if(m_map.size() > 5)
479+
m_map.erase(m_map.begin());
480+
481+
m_map.emplace_back(
482+
Cache{str, std::move(comp), {}, std::unique_ptr<QQuickItem>(script)});
483+
return script;
484+
}
485+
else
486+
{
487+
process.errorMessage(0, "The component must be of type Script");
488+
if(obj)
489+
delete obj;
490+
return nullptr;
491+
}
492+
}
493+
}
315494

316495
void ProcessModel::loadPreset(const Process::Preset& preset)
317496
{

src/plugins/score-plugin-js/JS/JSProcessModel.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ struct ComponentCache
2525
public:
2626
JS::Script*
2727
get(const JS::ProcessModel& process, const QByteArray& str, bool isFile) noexcept;
28+
QQuickItem* getUi(const JS::ProcessModel& process, const QByteArray& str) noexcept;
2829
JS::Script* tryGet(const QByteArray& str, bool isFile) const noexcept;
30+
QQuickItem* tryGet(const QByteArray& str) const noexcept;
2931
ComponentCache();
3032
~ComponentCache();
3133

@@ -35,6 +37,7 @@ struct ComponentCache
3537
QByteArray key;
3638
std::unique_ptr<QQmlComponent> component{};
3739
std::unique_ptr<JS::Script> object{};
40+
std::unique_ptr<QQuickItem> item{};
3841
};
3942
std::vector<Cache> m_map;
4043
};
@@ -60,10 +63,14 @@ class SCORE_PLUGIN_JS_EXPORT ProcessModel final : public Process::ProcessModel
6063

6164
[[nodiscard]] Process::ScriptChangeResult setScript(const QString& script);
6265
const QString& script() const noexcept { return m_script; }
63-
6466
const QByteArray& qmlData() const noexcept { return m_qmlData; }
6567

68+
[[nodiscard]] Process::ScriptChangeResult setUiScript(const QString& script);
69+
const QString& uiScript() const noexcept { return m_ui_script; }
70+
const QByteArray& uiQmlData() const noexcept { return m_ui_qmlData; }
71+
6672
JS::Script* currentObject() const noexcept;
73+
QQuickItem* currentUI() const noexcept;
6774
bool isGpu() const noexcept;
6875

6976
~ProcessModel() override;
@@ -73,17 +80,24 @@ class SCORE_PLUGIN_JS_EXPORT ProcessModel final : public Process::ProcessModel
7380
W_SIGNAL(errorMessage, arg_1, arg_2);
7481
void scriptOk() W_SIGNAL(scriptOk);
7582
void scriptChanged(const QString& arg_1) W_SIGNAL(scriptChanged, arg_1);
83+
void uiScriptChanged(const QString& arg_1) W_SIGNAL(uiScriptChanged, arg_1);
7684
void programChanged() W_SIGNAL(programChanged);
7785

7886
PROPERTY(QString, script READ script WRITE setScript NOTIFY scriptChanged)
87+
PROPERTY(QString, uiScript READ uiScript WRITE setUiScript NOTIFY uiScriptChanged)
7988
private:
8089
QString effect() const noexcept override;
8190
void loadPreset(const Process::Preset& preset) override;
8291
Process::Preset savePreset() const noexcept override;
8392
Process::ScriptChangeResult setQmlData(const QByteArray&, bool isFile);
93+
Process::ScriptChangeResult setUiQmlData(const QByteArray&);
8494

8595
QString m_script;
8696
QByteArray m_qmlData;
97+
98+
QString m_ui_script;
99+
QByteArray m_ui_qmlData;
100+
87101
mutable ComponentCache m_cache;
88102
bool m_isFile{};
89103
};

0 commit comments

Comments
 (0)