Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions src/plugins/score-lib-process/Process/ProcessFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,27 @@ score::ResizeableItem* LayerFactory::makeItem(
return nullptr;
}

bool LayerFactory::hasCodeEditor(
const ProcessModel&, const score::DocumentContext& ctx) const noexcept
{
return false;
}
QWidget* LayerFactory::makeCodeEditor(
const ProcessModel&, const score::DocumentContext& ctx, QWidget* parent) const
{
return nullptr;
}

bool LayerFactory::hasExternalUI(
const ProcessModel&, const score::DocumentContext& ctx) const noexcept
{
return false;
}
QWidget* LayerFactory::makeExternalUI(
ProcessModel&, const score::DocumentContext& ctx, QWidget* parent) const
{
return nullptr;
}

HeaderDelegate* LayerFactory::makeHeaderDelegate(
const ProcessModel& model, const Process::Context& ctx, QGraphicsItem* parent) const
Expand All @@ -123,12 +139,6 @@ FooterDelegate* LayerFactory::makeFooterDelegate(
return new DefaultFooterDelegate{model, ctx};
}

QWidget* LayerFactory::makeExternalUI(
ProcessModel&, const score::DocumentContext& ctx, QWidget* parent) const
{
return nullptr;
}

bool LayerFactory::matches(const ProcessModel& p) const
{
return matches(p.concreteKey());
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/score-lib-process/Process/ProcessFactory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ class SCORE_LIB_PROCESS_EXPORT LayerFactory : public score::InterfaceBase
const Process::ProcessModel&, const Process::Context& ctx,
QGraphicsItem* parent) const;

virtual bool hasCodeEditor(
const Process::ProcessModel& proc,
const score::DocumentContext& ctx) const noexcept;
virtual QWidget* makeCodeEditor(
const Process::ProcessModel&, const score::DocumentContext& ctx,
QWidget* parent) const;

virtual bool hasExternalUI(
const Process::ProcessModel& proc,
const score::DocumentContext& ctx) const noexcept;
Expand Down
225 changes: 187 additions & 38 deletions src/plugins/score-plugin-js/JS/JSProcessModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QQmlComponent>
#include <QQuickItem>
#include <QQuickWindow>

#include <wobjectimpl.h>

Expand All @@ -36,7 +38,6 @@
W_OBJECT_IMPL(JS::ProcessModel)
namespace JS
{

ProcessModel::ProcessModel(
const TimeVal& duration, const QString& data, const Id<Process::ProcessModel>& id,
QObject* parent)
Expand All @@ -58,16 +59,86 @@ Script {
out1.value = in1.value + sl.value * Math.random();
}
}
start: function() { console.log("I am called on start"); }
stop: function() { console.log("I am called on stop"); }
pause: function() { console.log("I am called on pause"); }
resume: function() { console.log("I am called on resume"); }
start: function() { }
stop: function() { }
pause: function() { }
resume: function() { }
})_");
}
else
{
(void)setScript(data);
}

setUiScript(R"_(import QtQuick
import QtQuick3D

View3D {
id: view
anchors.fill: parent

//! [environment]
environment: SceneEnvironment {
clearColor: "skyblue"
backgroundMode: SceneEnvironment.Color
}
//! [environment]

//! [camera]
PerspectiveCamera {
position: Qt.vector3d(0, 200, 300)
eulerRotation.x: -30
}
//! [camera]

//! [light]
DirectionalLight {
eulerRotation.x: -30
eulerRotation.y: -70
}
//! [light]

//! [objects]
Model {
position: Qt.vector3d(0, -200, 0)
source: "#Cylinder"
scale: Qt.vector3d(2, 0.2, 1)
materials: [ DefaultMaterial {
diffuseColor: "red"
}
]
}

Model {
position: Qt.vector3d(0, 150, 0)
source: "#Sphere"

materials: [ DefaultMaterial {
diffuseColor: "blue"
}
]

//! [animation]
SequentialAnimation on y {
loops: Animation.Infinite
NumberAnimation {
duration: 3000
to: -150
from: 150
easing.type:Easing.InQuad
}
NumberAnimation {
duration: 3000
to: 150
from: -150
easing.type:Easing.OutQuad
}
}
//! [animation]
}
//! [objects]
}
)_");
metadata().setInstanceName(*this);
}

Expand All @@ -92,53 +163,59 @@ bool ProcessModel::validate(const QString& script) const noexcept
}
}

[[nodiscard]] Process::ScriptChangeResult
ProcessModel::setUiScript(const QString& script)
{
Process::ScriptChangeResult res;
const auto trimmed = script.trimmed();
const QByteArray data = trimmed.toUtf8();

if(res = setUiQmlData(data); !res.valid)
return res;

m_ui_script = script;
uiScriptChanged(script);
res.valid = true;
return res;
}

QString ProcessModel::effect() const noexcept
{
return m_qmlData;
}

Process::ScriptChangeResult ProcessModel::setUiQmlData(const QByteArray& data)
{
Process::ScriptChangeResult res;
if(!data.contains("import QtQuick"))
return res;

auto script = m_cache.getUi(*this, data);
if(!script)
return res;

m_ui_qmlData = data;
res.valid = true;
// FIXME signal?

auto win = new QQuickWindow;
win->setWidth(640);
win->setHeight(640);
script->setParentItem(win->contentItem());
win->show();
return res;
}

[[nodiscard]] Process::ScriptChangeResult ProcessModel::setScript(const QString& script)
{
Process::ScriptChangeResult res;
/*
m_watch.reset();

if (m_dummyObject)
m_dummyObject->deleteLater();
m_dummyObject = nullptr;
m_dummyComponent.reset();
m_dummyComponent = std::make_unique<QQmlComponent>(&m_dummyEngine);
*/
const auto trimmed = script.trimmed();
const QByteArray data = trimmed.toUtf8();

auto path = score::locateFilePath(trimmed, score::IDocument::documentContext(*this));

if(QFileInfo{path}.exists())
{
/* Disabling the watch feature for now :
* it does not fix the cables, etc.
m_watch = std::make_unique<QFileSystemWatcher>(QStringList{trimmed});
connect(
m_watch.get(),
&QFileSystemWatcher::fileChanged,
this,
[=](const QString& path) {
// Note:
//
https://stackoverflow.com/questions/18300376/qt-qfilesystemwatcher-signal-filechanged-gets-emited-only-once
QTimer::singleShot(20, this, [this, path] {
m_watch->addPath(path);
QFile f(path);
if (f.open(QIODevice::ReadOnly))
{
setQmlData(path.toUtf8(), true);
m_watch->addPath(path);
}
});
});

*/
if(res = setQmlData(path.toUtf8(), true); !res.valid)
return res;
}
Expand All @@ -156,7 +233,7 @@ QString ProcessModel::effect() const noexcept
Process::ScriptChangeResult ProcessModel::setQmlData(const QByteArray& data, bool isFile)
{
Process::ScriptChangeResult res;
if(!isFile && !data.startsWith("import"))
if(!isFile && !data.contains("import "))
return res;

auto script = m_cache.get(*this, data, isFile);
Expand Down Expand Up @@ -223,6 +300,11 @@ Script* ProcessModel::currentObject() const noexcept
return m_cache.tryGet(m_qmlData, m_isFile);
}

QQuickItem* ProcessModel::currentUI() const noexcept
{
return m_cache.tryGet(m_ui_qmlData);
}

bool ProcessModel::isGpu() const noexcept
{
#if defined(SCORE_HAS_GPU_JS)
Expand All @@ -237,6 +319,19 @@ bool ProcessModel::isGpu() const noexcept
ComponentCache::ComponentCache() { }
ComponentCache::~ComponentCache() { }

QQuickItem* ComponentCache::tryGet(const QByteArray& str) const noexcept
{
auto it = ossia::find_if(m_map, [&](const auto& k) { return k.key == str; });
if(it != m_map.end())
{
return it->item.get();
}
else
{
return nullptr;
}
}

Script* ComponentCache::tryGet(const QByteArray& str, bool isFile) const noexcept
{
QByteArray content;
Expand Down Expand Up @@ -335,6 +430,60 @@ Script* ComponentCache::get(
}
}
}
QQuickItem*
ComponentCache::getUi(const ProcessModel& process, const QByteArray& str) noexcept
{
auto it = ossia::find_if(m_map, [&](const auto& k) { return k.key == str; });
if(it != m_map.end())
{
return it->item.get();
}
else
{
// FIXME put in applicationplugin instead, can't be global
static std::once_flag qml_dummy_engine_setup;
static QQmlEngine dummyEngine;
std::call_once(qml_dummy_engine_setup, [] { setupEngineImportPaths(dummyEngine); });

auto comp = std::make_unique<QQmlComponent>(&dummyEngine);
{
auto& lib = score::AppContext().settings<Library::Settings::Model>();
// FIXME QTBUG-107204
QString path = lib.getDefaultLibraryPath() + QDir::separator() + "Scripts"
+ QDir::separator() + "include" + QDir::separator() + "Script.qml";
comp->setData(str, QUrl::fromLocalFile(path));
}
const auto& errs = comp->errors();
if(!errs.empty())
{
const auto& err = errs.first();
qDebug() << err.line() << err.toString();
auto str = err.toString();
str.remove("<Unknown File>:");
process.errorMessage(err.line(), str);
return nullptr;
}

auto obj = comp->create();
auto script = qobject_cast<QQuickItem*>(obj);
if(script)
{
if(m_map.size() > 5)
m_map.erase(m_map.begin());

m_map.emplace_back(
Cache{str, std::move(comp), {}, std::unique_ptr<QQuickItem>(script)});
return script;
}
else
{
process.errorMessage(0, "The component must be of type Script");
if(obj)
delete obj;
return nullptr;
}
}
}

void ProcessModel::loadPreset(const Process::Preset& preset)
{
Expand Down
Loading
Loading