Skip to content

Commit

Permalink
[js] WIP on enumerating devices from js / qml
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Nov 22, 2024
1 parent a8be8fb commit 8731738
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/lib/score/document/DocumentContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ struct SCORE_LIB_BASE_EXPORT DocumentContext

using MaybeDocument = const score::DocumentContext*;
}

W_REGISTER_ARGTYPE(score::DocumentContext*)
W_REGISTER_ARGTYPE(const score::DocumentContext*)
2 changes: 2 additions & 0 deletions src/plugins/score-plugin-js/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ set(HDRS

"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/AddressItem.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/DeviceContext.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/DeviceEnumerator.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/EditContext.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/QmlObjects.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/ValueTypes.${QT_PREFIX}.hpp"
Expand Down Expand Up @@ -58,6 +59,7 @@ set(SRCS

"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/AddressItem.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/DeviceContext.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/DeviceEnumerator.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/EditContext.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/EditContext.curve.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/JS/Qml/EditContext.device.cpp"
Expand Down
114 changes: 114 additions & 0 deletions src/plugins/score-plugin-js/JS/Qml/DeviceEnumerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include "DeviceEnumerator.hpp"

#include <Device/Protocol/ProtocolFactoryInterface.hpp>
#include <Device/Protocol/ProtocolList.hpp>

#include <Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp>

#include <wobjectimpl.h>
W_OBJECT_IMPL(JS::GlobalDeviceEnumerator)
namespace JS
{
/**
var e = Score.enumerateDevices();
e.enumerate = true;
console.log(e.devices);
*/

GlobalDeviceEnumerator::GlobalDeviceEnumerator() { }
GlobalDeviceEnumerator::~GlobalDeviceEnumerator()
{
m_enumerate = false;
reprocess();
}

void GlobalDeviceEnumerator::setContext(const score::DocumentContext* doc)
{
this->doc = doc;
reprocess();
//list = &doc.plugin<Explorer::DeviceDocumentPlugin>();
}

QQmlListProperty<DeviceIdentifier> GlobalDeviceEnumerator::devices()
{

return QQmlListProperty<DeviceIdentifier>(
this, nullptr, [](QQmlListProperty<DeviceIdentifier>* d) -> long long {
qDebug() << "sz: " << ((GlobalDeviceEnumerator*)d->object)->m_raw_list.size();
return ((GlobalDeviceEnumerator*)d->object)->m_raw_list.size();
}, [](QQmlListProperty<DeviceIdentifier>* d, qsizetype index) -> DeviceIdentifier* {
auto self = (GlobalDeviceEnumerator*)d->object;
qDebug() << "sz: " << self->m_raw_list.size() << " => " << index;
if(index >= 0 && index < self->m_raw_list.size())
return self->m_raw_list[index];
else
return nullptr;
});
}
void GlobalDeviceEnumerator::setEnumerate(bool b)
{
if(m_enumerate == b)
return;

m_enumerate = b;
enumerateChanged(b);

reprocess();
}

void GlobalDeviceEnumerator::reprocess()
{
for(auto& [k, v] : this->m_current_enums)
{
for(auto& [ename, e] : v)
delete e;
}
this->m_current_enums.clear();
this->m_known_devices.clear();

if(!this->doc)
return;
if(!this->m_enumerate)
return;

auto& doc = *this->doc;
for(auto& protocol : doc.app.interfaces<Device::ProtocolFactoryList>())
{
auto enums = protocol.getEnumerators(doc);
for(auto& [name, enumerator] : enums)
{
connect(
enumerator, &Device::DeviceEnumerator::deviceAdded, this,
[this,
proto = &protocol](const QString& name, const Device::DeviceSettings& devs) {
this->deviceAdded(proto, name, devs);
this->m_known_devices[proto].emplace_back(name, devs);
m_raw_list.push_back(
new DeviceIdentifier{.name = name, .settings = devs, .protocol = proto});
},
Qt::QueuedConnection);
connect(
enumerator, &Device::DeviceEnumerator::deviceRemoved, this,
[this, proto = &protocol](const QString& name) {
this->deviceRemoved(proto, name);
{
auto& vec = this->m_known_devices[proto];
auto it = ossia::find_key(vec, name);
if(it != vec.end())
vec.erase(it);
}
{
auto it = ossia::find_if(this->m_raw_list, [&](auto& di) {
return di->protocol == proto && di->name == name;
});
if(it != this->m_raw_list.end())
{
delete *it;
this->m_raw_list.erase(it);
}
}
}, Qt::QueuedConnection);
}
}
}
}
77 changes: 77 additions & 0 deletions src/plugins/score-plugin-js/JS/Qml/DeviceEnumerator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

#include <Device/Protocol/DeviceSettings.hpp>
#include <Device/Protocol/ProtocolFactoryInterface.hpp>

#include <QQmlListProperty>

#include <unordered_map>
#include <verdigris>

namespace Explorer
{
class DeviceDocumentPlugin;
}
namespace Device
{
struct DeviceSettings;
class DeviceList;
class ProtocolFactory;
class DeviceEnumerator;
}

namespace JS
{
struct DeviceIdentifier
{
W_GADGET(DeviceIdentifier)
public:
QString name;
Device::DeviceSettings settings;
Device::ProtocolFactory* protocol{};
};

class GlobalDeviceEnumerator : public QObject
{
W_OBJECT(GlobalDeviceEnumerator)

public:
explicit GlobalDeviceEnumerator();
~GlobalDeviceEnumerator();

void setContext(const score::DocumentContext* doc);
W_SLOT(setContext)

void deviceAdded(
Device::ProtocolFactory* factory, const QString& name,
Device::DeviceSettings settings) W_SIGNAL(deviceAdded, factory, name, settings)
void deviceRemoved(Device::ProtocolFactory* factory, const QString& name)
W_SIGNAL(deviceRemoved, factory, name)
// QList<Device::DeviceSettings> devices();
QQmlListProperty<JS::DeviceIdentifier> devices();

W_PROPERTY(QQmlListProperty<JS::DeviceIdentifier>, devices READ devices)

bool enumerate() { return m_enumerate; }
void setEnumerate(bool b);
void enumerateChanged(bool b) W_SIGNAL(enumerateChanged, b)
W_PROPERTY(bool, enumerate READ enumerate WRITE setEnumerate NOTIFY enumerateChanged)

private:
void reprocess();
const score::DocumentContext* doc{};

std::unordered_map<
Device::ProtocolFactory*, std::vector<std::pair<QString, Device::DeviceSettings>>>
m_known_devices;
std::unordered_map<Device::ProtocolFactory*, Device::DeviceEnumerators>
m_current_enums;

std::vector<DeviceIdentifier*> m_raw_list;

bool m_enumerate{};
};
}

Q_DECLARE_METATYPE(JS::GlobalDeviceEnumerator*)
W_REGISTER_ARGTYPE(Device::ProtocolFactory*)
1 change: 0 additions & 1 deletion src/plugins/score-plugin-js/JS/Qml/EditContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,4 @@ QVariantList EditJsContext::selectedObjects()
list.push_back(QVariant::fromValue(c.data()));
return list;
}

}
12 changes: 12 additions & 0 deletions src/plugins/score-plugin-js/JS/Qml/EditContext.device.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <Explorer/DocumentPlugin/DeviceDocumentPlugin.hpp>

#include <JS/Qml/DeviceEnumerator.hpp>
#include <JS/Qml/EditContext.hpp>

#include <ossia-config.hpp>
Expand All @@ -25,6 +26,17 @@
#include <ossia/preset/preset.hpp>
namespace JS
{
GlobalDeviceEnumerator* EditJsContext::enumerateDevices()
{
auto doc = ctx();
if(!doc)
return nullptr;

auto e = new GlobalDeviceEnumerator{};
e->setContext(doc);
// e->setEnumerate(true);
return e;
}

void EditJsContext::createOSCDevice(QString name, QString host, int in, int out)
{ /*
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/score-plugin-js/JS/Qml/EditContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ namespace Scenario::Command
{
class Macro;
}

namespace JS
{
class GlobalDeviceEnumerator;
class EditJsContext : public QObject
{
W_OBJECT(EditJsContext)
Expand All @@ -39,6 +39,7 @@ class EditJsContext : public QObject
~EditJsContext();

const score::DocumentContext* ctx();
W_INVOKABLE(ctx);

QString deviceToJson(QString addr);
W_SLOT(deviceToJson)
Expand All @@ -52,6 +53,9 @@ class EditJsContext : public QObject
void createQMLSerialDevice(QString name, QString port, QString text);
W_SLOT(createQMLSerialDevice)

GlobalDeviceEnumerator* enumerateDevices();
W_SLOT(enumerateDevices)

void createAddress(QString addr, QString type);
W_SLOT(createAddress)

Expand Down Expand Up @@ -216,3 +220,4 @@ class EditJsContext : public QObject

W_REGISTER_ARGTYPE(QVector<QVariantList>)
W_REGISTER_ARGTYPE(QList<QObject*>)
W_REGISTER_ARGTYPE(JS::GlobalDeviceEnumerator*)
3 changes: 3 additions & 0 deletions src/plugins/score-plugin-js/score_plugin_js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <JS/JSProcessFactory.hpp>
#include <JS/LibraryHandler.hpp>
#include <JS/Qml/AddressItem.hpp>
#include <JS/Qml/DeviceEnumerator.hpp>
#include <JS/Qml/PortSource.hpp>
#include <JS/Qml/QmlObjects.hpp>
#include <JS/Qml/Utils.hpp>
Expand Down Expand Up @@ -76,12 +77,14 @@ score_plugin_js::score_plugin_js()

qmlRegisterType<JS::AddressSource>("Score", 1, 0, "AddressSource");
qmlRegisterType<JS::PortSource>("Score", 1, 0, "PortSource");
qmlRegisterType<JS::GlobalDeviceEnumerator>("Score", 1, 0, "DeviceEnumerator");

qRegisterMetaType<QVector<JS::MidiMessage>>();

qRegisterMetaType<JS::SampleTimings>();
qRegisterMetaType<JS::TokenRequestValueType>();
qRegisterMetaType<JS::ExecutionStateValueType>();
//qRegisterMetaType<JS::GlobalDeviceEnumerator>();
}

score_plugin_js::~score_plugin_js() = default;
Expand Down

0 comments on commit 8731738

Please sign in to comment.