From d94da76b7260006eea22faed07e99d0c57077e81 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 13 Dec 2016 10:42:36 -0800 Subject: [PATCH 1/4] Added TabletScriptingInterface --- interface/src/scripting/QmlWrapper.h | 63 +++++++++++++++++++ .../scripting/TabletScriptingInterface.cpp | 33 ++++++++++ .../src/scripting/TabletScriptingInterface.h | 31 +++++++++ .../scripting/ToolbarScriptingInterface.cpp | 51 +-------------- 4 files changed, 129 insertions(+), 49 deletions(-) create mode 100644 interface/src/scripting/QmlWrapper.h create mode 100644 interface/src/scripting/TabletScriptingInterface.cpp create mode 100644 interface/src/scripting/TabletScriptingInterface.h diff --git a/interface/src/scripting/QmlWrapper.h b/interface/src/scripting/QmlWrapper.h new file mode 100644 index 0000000000..7dd319e445 --- /dev/null +++ b/interface/src/scripting/QmlWrapper.h @@ -0,0 +1,63 @@ +// +// Created by Anthony J. Thibault on 2016-12-12 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_QmlWrapper_h +#define hifi_QmlWrapper_h + +#include +#include +#include + +class QmlWrapper : public QObject { + Q_OBJECT +public: + QmlWrapper(QObject* qmlObject, QObject* parent = nullptr) + : QObject(parent), _qmlObject(qmlObject) { + } + + Q_INVOKABLE void writeProperty(QString propertyName, QVariant propertyValue) { + auto offscreenUi = DependencyManager::get(); + offscreenUi->executeOnUiThread([=] { + _qmlObject->setProperty(propertyName.toStdString().c_str(), propertyValue); + }); + } + + Q_INVOKABLE void writeProperties(QVariant propertyMap) { + auto offscreenUi = DependencyManager::get(); + offscreenUi->executeOnUiThread([=] { + QVariantMap map = propertyMap.toMap(); + for (const QString& key : map.keys()) { + _qmlObject->setProperty(key.toStdString().c_str(), map[key]); + } + }); + } + + Q_INVOKABLE QVariant readProperty(const QString& propertyName) { + auto offscreenUi = DependencyManager::get(); + return offscreenUi->returnFromUiThread([&]()->QVariant { + return _qmlObject->property(propertyName.toStdString().c_str()); + }); + } + + Q_INVOKABLE QVariant readProperties(const QVariant& propertyList) { + auto offscreenUi = DependencyManager::get(); + return offscreenUi->returnFromUiThread([&]()->QVariant { + QVariantMap result; + for (const QVariant& property : propertyList.toList()) { + QString propertyString = property.toString(); + result.insert(propertyString, _qmlObject->property(propertyString.toStdString().c_str())); + } + return result; + }); + } + +protected: + QObject* _qmlObject{ nullptr }; +}; + +#endif \ No newline at end of file diff --git a/interface/src/scripting/TabletScriptingInterface.cpp b/interface/src/scripting/TabletScriptingInterface.cpp new file mode 100644 index 0000000000..05b34cf675 --- /dev/null +++ b/interface/src/scripting/TabletScriptingInterface.cpp @@ -0,0 +1,33 @@ +// +// Created by Bradley Austin Davis on 2016-06-16 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TabletScriptingInterface.h" + +#include + +#include +#include "QmlWrapper.h" + +class TabletButtonProxy : public QmlWrapper { + Q_OBJECT + +public: + TabletButtonProxy(QObject* qmlObject, QObject* parent = nullptr) : QmlWrapper(qmlObject, parent) { + connect(qmlObject, SIGNAL(clicked()), this, SIGNAL(clicked())); + } + +signals: + void clicked(); +}; + +QObject* TabletScriptingInterface::getTablet(const QString& tabletId) { + // AJT TODO: how the fuck do I get access to the toolbar qml?!? from here? + return nullptr; +} + +#include "TabletScriptingInterface.moc" diff --git a/interface/src/scripting/TabletScriptingInterface.h b/interface/src/scripting/TabletScriptingInterface.h new file mode 100644 index 0000000000..8829894bbd --- /dev/null +++ b/interface/src/scripting/TabletScriptingInterface.h @@ -0,0 +1,31 @@ +// +// Created by Anthony J. Thibault on 2016-12-12 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_TabletScriptingInterface_h +#define hifi_TabletScriptingInterface_h + +#include + +#include + +/**jsdoc + * @namespace Tablet + */ +class TabletScriptingInterface : public QObject, public Dependency { + Q_OBJECT +public: + /**jsdoc + * Creates a new button on the tablet ui and returns it. + * @function Tablet.getTablet + * @param name {String} tablet name + * @return {QmlWrapper} tablet instance + */ + Q_INVOKABLE QObject* getTablet(const QString& tabletId); +}; + +#endif // hifi_TabletScriptingInterface_h diff --git a/interface/src/scripting/ToolbarScriptingInterface.cpp b/interface/src/scripting/ToolbarScriptingInterface.cpp index 0cb314615a..1f2228c6d9 100644 --- a/interface/src/scripting/ToolbarScriptingInterface.cpp +++ b/interface/src/scripting/ToolbarScriptingInterface.cpp @@ -8,58 +8,11 @@ #include "ToolbarScriptingInterface.h" + #include #include - -class QmlWrapper : public QObject { - Q_OBJECT -public: - QmlWrapper(QObject* qmlObject, QObject* parent = nullptr) - : QObject(parent), _qmlObject(qmlObject) { - } - - Q_INVOKABLE void writeProperty(QString propertyName, QVariant propertyValue) { - auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([=] { - _qmlObject->setProperty(propertyName.toStdString().c_str(), propertyValue); - }); - } - - Q_INVOKABLE void writeProperties(QVariant propertyMap) { - auto offscreenUi = DependencyManager::get(); - offscreenUi->executeOnUiThread([=] { - QVariantMap map = propertyMap.toMap(); - for (const QString& key : map.keys()) { - _qmlObject->setProperty(key.toStdString().c_str(), map[key]); - } - }); - } - - Q_INVOKABLE QVariant readProperty(const QString& propertyName) { - auto offscreenUi = DependencyManager::get(); - return offscreenUi->returnFromUiThread([&]()->QVariant { - return _qmlObject->property(propertyName.toStdString().c_str()); - }); - } - - Q_INVOKABLE QVariant readProperties(const QVariant& propertyList) { - auto offscreenUi = DependencyManager::get(); - return offscreenUi->returnFromUiThread([&]()->QVariant { - QVariantMap result; - for (const QVariant& property : propertyList.toList()) { - QString propertyString = property.toString(); - result.insert(propertyString, _qmlObject->property(propertyString.toStdString().c_str())); - } - return result; - }); - } - - -protected: - QObject* _qmlObject{ nullptr }; -}; - +#include "QmlWrapper.h" class ToolbarButtonProxy : public QmlWrapper { Q_OBJECT From db0b2ba7d3a1e624652c2a640abcdc8fc5741dab Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 13 Dec 2016 16:52:02 -0800 Subject: [PATCH 2/4] Fleshing out TabletScriptingInterface. Added TabletProxy and TabletButtonProxy --- interface/src/Application.cpp | 4 + .../scripting/TabletScriptingInterface.cpp | 81 +++++++++++++++---- .../src/scripting/TabletScriptingInterface.h | 79 +++++++++++++++++- 3 files changed, 145 insertions(+), 19 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5eca9590dd..7014cb400c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -144,6 +144,7 @@ #include "scripting/SettingsScriptingInterface.h" #include "scripting/WindowScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h" +#include "scripting/TabletScriptingInterface.h" #include "scripting/ToolbarScriptingInterface.h" #include "scripting/RatesScriptingInterface.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) @@ -478,6 +479,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -5181,6 +5183,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Reticle", getApplicationCompositor().getReticleInterface()); + scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); diff --git a/interface/src/scripting/TabletScriptingInterface.cpp b/interface/src/scripting/TabletScriptingInterface.cpp index 05b34cf675..0899460092 100644 --- a/interface/src/scripting/TabletScriptingInterface.cpp +++ b/interface/src/scripting/TabletScriptingInterface.cpp @@ -10,24 +10,71 @@ #include -#include -#include "QmlWrapper.h" - -class TabletButtonProxy : public QmlWrapper { - Q_OBJECT - -public: - TabletButtonProxy(QObject* qmlObject, QObject* parent = nullptr) : QmlWrapper(qmlObject, parent) { - connect(qmlObject, SIGNAL(clicked()), this, SIGNAL(clicked())); - } - -signals: - void clicked(); -}; - QObject* TabletScriptingInterface::getTablet(const QString& tabletId) { - // AJT TODO: how the fuck do I get access to the toolbar qml?!? from here? - return nullptr; + + std::lock_guard guard(_tabletProxiesMutex); + + // look up tabletId in the map. + auto iter = _tabletProxies.find(tabletId); + if (iter != _tabletProxies.end()) { + // tablet already exists, just return it. + return iter->second.data(); + } else { + // allocate a new tablet, add it to the map then return it. + auto tabletProxy = QSharedPointer(new TabletProxy(tabletId)); + _tabletProxies[tabletId] = tabletProxy; + return tabletProxy.data(); + } +} + +// +// TabletProxy +// + +TabletProxy::TabletProxy(QString name) : _name(name) { + ; +} + +QObject* TabletProxy::addButton(const QVariant& properties) { + auto tabletButtonProxy = QSharedPointer(new TabletButtonProxy(properties.toMap())); + std::lock_guard guard(_tabletButtonProxiesMutex); + _tabletButtonProxies.push_back(tabletButtonProxy); + return tabletButtonProxy.data(); +} + +void TabletProxy::removeButton(QObject* tabletButtonProxy) { + std::lock_guard guard(_tabletButtonProxiesMutex); + auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy); + if (iter != _tabletButtonProxies.end()) { + _tabletButtonProxies.erase(iter); + } else { + qWarning() << "TabletProxy::removeButton() could not find button " << tabletButtonProxy; + } +} + +// +// TabletButtonProxy +// + +TabletButtonProxy::TabletButtonProxy(const QVariantMap& properties) : _properties(properties) { + ; +} + +void TabletButtonProxy::setInitRequestHandler(const QScriptValue& handler) { + _initRequestHandler = handler; +} + +static QString IMAGE_URL_KEY = "imageUrl"; +static QString IMAGE_URL_DEFAULT = ""; + +QString TabletButtonProxy::getImageUrl() const { + std::lock_guard guard(_propertiesMutex); + return _properties.value(IMAGE_URL_KEY, IMAGE_URL_DEFAULT).toString(); +} + +void TabletButtonProxy::setImageUrl(QString imageUrl) { + std::lock_guard guard(_propertiesMutex); + _properties[IMAGE_URL_KEY] = imageUrl; } #include "TabletScriptingInterface.moc" diff --git a/interface/src/scripting/TabletScriptingInterface.h b/interface/src/scripting/TabletScriptingInterface.h index 8829894bbd..48407f823c 100644 --- a/interface/src/scripting/TabletScriptingInterface.h +++ b/interface/src/scripting/TabletScriptingInterface.h @@ -9,10 +9,18 @@ #ifndef hifi_TabletScriptingInterface_h #define hifi_TabletScriptingInterface_h +#include + #include +#include +#include #include + +class TabletProxy; +class TabletButtonProxy; + /**jsdoc * @namespace Tablet */ @@ -20,12 +28,79 @@ class TabletScriptingInterface : public QObject, public Dependency { Q_OBJECT public: /**jsdoc - * Creates a new button on the tablet ui and returns it. + * Creates or retruns a new TabletProxy and returns it. * @function Tablet.getTablet * @param name {String} tablet name - * @return {QmlWrapper} tablet instance + * @return {TabletProxy} tablet instance */ Q_INVOKABLE QObject* getTablet(const QString& tabletId); +protected: + std::mutex _tabletProxiesMutex; + std::map> _tabletProxies; +}; + +/**jsdoc + * @class TabletProxy + * @property name {string} name of this tablet + */ +class TabletProxy : public QObject { + Q_OBJECT + Q_PROPERTY(QString name READ getName) +public: + TabletProxy(QString name); + + /**jsdoc + * @function TabletProxy#addButton + * Creates a new button, adds it to this and returns it. + * @param properties {Object} button properties AJT: TODO: enumerate these... + * @returns {TabletButtonProxy} + */ + Q_INVOKABLE QObject* addButton(const QVariant& properties); + + /**jsdoc + * @function TabletProxy#removeButton + * removes button from the tablet + * @param tabletButtonProxy {TabletButtonProxy} button to be removed + */ + Q_INVOKABLE void removeButton(QObject* tabletButtonProxy); + + QString getName() const { return _name; } +protected: + QString _name; + std::mutex _tabletButtonProxiesMutex; + std::vector> _tabletButtonProxies; +}; + +/**jsdoc + * @class TabletButtonProxy + * @property imageUrl {string} + */ +class TabletButtonProxy : public QObject { + Q_OBJECT + Q_PROPERTY(QString imageUrl READ getImageUrl WRITE setImageUrl) +public: + TabletButtonProxy(const QVariantMap& properties); + + /**jsdoc + * @function TabletButtonProxy#setInitRequestHandler + * @param handler {Function} A function used by the system to request the current button state from JavaScript. + */ + Q_INVOKABLE void setInitRequestHandler(const QScriptValue& handler); + + QString getImageUrl() const; + void setImageUrl(QString imageUrl); + +signals: + /**jsdoc + * Signaled when this button has been clicked on by the user. + * @function TabletButtonProxy#onClick + * @returns {Signal} + */ + void onClick(); +protected: + mutable std::mutex _propertiesMutex; + QVariantMap _properties; + QScriptValue _initRequestHandler; }; #endif // hifi_TabletScriptingInterface_h From d4f9d21ce8795b7c53e4ff23c47aa670d14bd85f Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 14 Dec 2016 14:04:48 -0800 Subject: [PATCH 3/4] Pass tablet QQuickItem to TabletScriptingInterface Also, moved TabletScriptingInterface to script-engine library for easy access, baby. --- interface/resources/qml/hifi/tablet/Tablet.qml | 1 + interface/src/Application.cpp | 4 +--- .../entities-renderer/src/RenderableWebEntityItem.cpp | 9 ++++++++- libraries/script-engine/src/ScriptEngine.cpp | 3 +++ .../script-engine/src}/TabletScriptingInterface.cpp | 5 +++++ .../script-engine/src}/TabletScriptingInterface.h | 3 +++ 6 files changed, 21 insertions(+), 4 deletions(-) rename {interface/src/scripting => libraries/script-engine/src}/TabletScriptingInterface.cpp (93%) rename {interface/src/scripting => libraries/script-engine/src}/TabletScriptingInterface.h (97%) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index c6b38b538f..1f45d6cf4c 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -3,6 +3,7 @@ import QtGraphicalEffects 1.0 Item { id: tablet + objectName: "tablet" property double miclevel: 0.8 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7014cb400c..a4d72a3e1d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -104,6 +104,7 @@ #include #include #include +#include #include #include #include @@ -144,7 +145,6 @@ #include "scripting/SettingsScriptingInterface.h" #include "scripting/WindowScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h" -#include "scripting/TabletScriptingInterface.h" #include "scripting/ToolbarScriptingInterface.h" #include "scripting/RatesScriptingInterface.h" #if defined(Q_OS_MAC) || defined(Q_OS_WIN) @@ -5183,8 +5183,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Reticle", getApplicationCompositor().getReticleInterface()); - scriptEngine->registerGlobalObject("Tablet", DependencyManager::get().data()); - scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index b48fd4263a..29f6a3afd1 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "EntityTreeRenderer.h" #include "EntitiesRendererLogging.h" @@ -255,7 +256,13 @@ void RenderableWebEntityItem::loadSourceURL() { } else { _contentType = qmlContent; _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath())); - _webSurface->load(_sourceUrl, [&](QQmlContext* context, QObject* obj) { }); + _webSurface->load(_sourceUrl, [&](QQmlContext* context, QObject* obj) {}); + + // TABLET_UI_HACK: move this to overlays as well! + if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tablet") { + auto tabletScriptingInterface = DependencyManager::get(); + tabletScriptingInterface->setupTablet("com.highfidelity.interface.tablet.system", _webSurface->getRootItem()); + } } } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 070bc98dbc..8e8ce6a851 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -62,6 +62,7 @@ #include "WebSocketClass.h" #include "RecordingScriptingInterface.h" #include "ScriptEngines.h" +#include "TabletScriptingInterface.h" #include "MIDIEvent.h" @@ -542,6 +543,8 @@ void ScriptEngine::init() { auto recordingInterface = DependencyManager::get(); registerGlobalObject("Recording", recordingInterface.data()); + registerGlobalObject("Tablet", DependencyManager::get().data()); + registerGlobalObject("Assets", &_assetScriptingInterface); registerGlobalObject("Resources", DependencyManager::get().data()); } diff --git a/interface/src/scripting/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp similarity index 93% rename from interface/src/scripting/TabletScriptingInterface.cpp rename to libraries/script-engine/src/TabletScriptingInterface.cpp index 0899460092..e1dd466f59 100644 --- a/interface/src/scripting/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -27,6 +27,11 @@ QObject* TabletScriptingInterface::getTablet(const QString& tabletId) { } } +void TabletScriptingInterface::setupTablet(QString tabletId, QQuickItem* qmlTablet) { + // AJT: TODO + qDebug() << "AJT: setupTablet objname = " << qmlTablet->objectName(); +} + // // TabletProxy // diff --git a/interface/src/scripting/TabletScriptingInterface.h b/libraries/script-engine/src/TabletScriptingInterface.h similarity index 97% rename from interface/src/scripting/TabletScriptingInterface.h rename to libraries/script-engine/src/TabletScriptingInterface.h index 48407f823c..ee2b22eed6 100644 --- a/interface/src/scripting/TabletScriptingInterface.h +++ b/libraries/script-engine/src/TabletScriptingInterface.h @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -34,6 +35,8 @@ public: * @return {TabletProxy} tablet instance */ Q_INVOKABLE QObject* getTablet(const QString& tabletId); + + void setupTablet(QString tabletId, QQuickItem* qmlTablet); protected: std::mutex _tabletProxiesMutex; std::map> _tabletProxies; From d2c4417b24d5dd78bf98d6ae35d553758b6184b5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 14 Dec 2016 17:05:47 -0800 Subject: [PATCH 4/4] Hook up Help button to the new Tablet interface --- .../resources/qml/hifi/tablet/Tablet.qml | 21 ++++++++ .../qml/hifi/tablet/TabletButton.qml | 3 ++ .../src/RenderableWebEntityItem.cpp | 2 +- .../src/TabletScriptingInterface.cpp | 54 +++++++++++++++++-- .../src/TabletScriptingInterface.h | 20 ++++--- scripts/system/help.js | 18 +++---- 6 files changed, 95 insertions(+), 23 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 1f45d6cf4c..4ea1891737 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -10,6 +10,27 @@ Item { width: 480 height: 720 + // called by C++ code when a button should be added to the tablet + function addButtonProxy(properties) { + var component = Qt.createComponent("TabletButton.qml"); + var button = component.createObject(flowMain); + if (properties.icon) { + button.icon = properties.icon; + } + if (properties.color) { + button.color = properties.color; + } + if (properties.text) { + button.text = properties.text; + } + return button; + } + + // called by C++ code when a button should be removed from the tablet + function removeButtonProxy(properties) { + console.log("TABLET_UI_HACK: removeButtonProxy, NOT IMPLEMENTED!, properties = " + JSON.stringify(properties)); + } + Rectangle { id: bgAudio height: 90 diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index 75f5423f41..92a7ee2865 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -9,6 +9,8 @@ Item { width: 132 height: 132 + signal clicked() + Rectangle { id: buttonBg color: tabletButton.color @@ -62,6 +64,7 @@ Item { MouseArea { anchors.fill: parent hoverEnabled: true + onClicked: tabletButton.clicked(); onEntered: { console.log("Tablet Button Hovered!"); tabletButton.state = "hover state"; diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 29f6a3afd1..cba6842ba9 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -261,7 +261,7 @@ void RenderableWebEntityItem::loadSourceURL() { // TABLET_UI_HACK: move this to overlays as well! if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tablet") { auto tabletScriptingInterface = DependencyManager::get(); - tabletScriptingInterface->setupTablet("com.highfidelity.interface.tablet.system", _webSurface->getRootItem()); + tabletScriptingInterface->setQmlTablet("com.highfidelity.interface.tablet.system", _webSurface->getRootItem()); } } } diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index e1dd466f59..1bcdfc6013 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -27,11 +27,16 @@ QObject* TabletScriptingInterface::getTablet(const QString& tabletId) { } } -void TabletScriptingInterface::setupTablet(QString tabletId, QQuickItem* qmlTablet) { - // AJT: TODO - qDebug() << "AJT: setupTablet objname = " << qmlTablet->objectName(); +void TabletScriptingInterface::setQmlTablet(QString tabletId, QQuickItem* qmlTablet) { + TabletProxy* tablet = qobject_cast(getTablet(tabletId)); + if (tablet) { + tablet->setQmlTablet(qmlTablet); + } else { + qWarning() << "TabletScriptingInterface::setupTablet() bad tablet object"; + } } + // // TabletProxy // @@ -40,10 +45,47 @@ TabletProxy::TabletProxy(QString name) : _name(name) { ; } +static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* buttonProxy) { + QVariant resultVar; + Qt::ConnectionType connectionType = Qt::AutoConnection; + if (QThread::currentThread() != qmlTablet->thread()) { + connectionType = Qt::BlockingQueuedConnection; + } + bool hasResult = QMetaObject::invokeMethod(qmlTablet, "addButtonProxy", connectionType, + Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, buttonProxy->getProperties())); + if (!hasResult) { + qWarning() << "TabletScriptingInterface addButtonProxyToQmlTablet has no result"; + return; + } + + QObject* qmlButton = qvariant_cast(resultVar); + if (!qmlButton) { + qWarning() << "TabletScriptingInterface addButtonProxyToQmlTablet result not a QObject"; + return; + } + QObject::connect(qmlButton, SIGNAL(clicked()), buttonProxy, SLOT(clickedSlot())); +} + +void TabletProxy::setQmlTablet(QQuickItem* qmlTablet) { + if (qmlTablet) { + _qmlTablet = qmlTablet; + std::lock_guard guard(_tabletButtonProxiesMutex); + for (auto& buttonProxy : _tabletButtonProxies) { + addButtonProxyToQmlTablet(_qmlTablet, buttonProxy.data()); + } + } else { + _qmlTablet = nullptr; + } + +} + QObject* TabletProxy::addButton(const QVariant& properties) { auto tabletButtonProxy = QSharedPointer(new TabletButtonProxy(properties.toMap())); std::lock_guard guard(_tabletButtonProxiesMutex); _tabletButtonProxies.push_back(tabletButtonProxy); + if (_qmlTablet) { + addButtonProxyToQmlTablet(_qmlTablet, tabletButtonProxy.data()); + } return tabletButtonProxy.data(); } @@ -51,6 +93,9 @@ void TabletProxy::removeButton(QObject* tabletButtonProxy) { std::lock_guard guard(_tabletButtonProxiesMutex); auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy); if (iter != _tabletButtonProxies.end()) { + if (_qmlTablet) { + QMetaObject::invokeMethod(_qmlTablet, "removeButton", Qt::AutoConnection, Q_ARG(QVariant, (*iter)->getProperties())); + } _tabletButtonProxies.erase(iter); } else { qWarning() << "TabletProxy::removeButton() could not find button " << tabletButtonProxy; @@ -69,6 +114,8 @@ void TabletButtonProxy::setInitRequestHandler(const QScriptValue& handler) { _initRequestHandler = handler; } +// TABLET_UI_HACK remove +/* static QString IMAGE_URL_KEY = "imageUrl"; static QString IMAGE_URL_DEFAULT = ""; @@ -81,5 +128,6 @@ void TabletButtonProxy::setImageUrl(QString imageUrl) { std::lock_guard guard(_propertiesMutex); _properties[IMAGE_URL_KEY] = imageUrl; } +*/ #include "TabletScriptingInterface.moc" diff --git a/libraries/script-engine/src/TabletScriptingInterface.h b/libraries/script-engine/src/TabletScriptingInterface.h index ee2b22eed6..13d7219306 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.h +++ b/libraries/script-engine/src/TabletScriptingInterface.h @@ -36,7 +36,8 @@ public: */ Q_INVOKABLE QObject* getTablet(const QString& tabletId); - void setupTablet(QString tabletId, QQuickItem* qmlTablet); + void setQmlTablet(QString tabletId, QQuickItem* qmlTablet); + protected: std::mutex _tabletProxiesMutex; std::map> _tabletProxies; @@ -52,10 +53,12 @@ class TabletProxy : public QObject { public: TabletProxy(QString name); + void setQmlTablet(QQuickItem* qmlTablet); + /**jsdoc * @function TabletProxy#addButton * Creates a new button, adds it to this and returns it. - * @param properties {Object} button properties AJT: TODO: enumerate these... + * @param properties {Object} button properties UI_TABLET_HACK: enumerate these when we figure out what they should be! * @returns {TabletButtonProxy} */ Q_INVOKABLE QObject* addButton(const QVariant& properties); @@ -72,6 +75,7 @@ protected: QString _name; std::mutex _tabletButtonProxiesMutex; std::vector> _tabletButtonProxies; + QQuickItem* _qmlTablet { nullptr }; }; /**jsdoc @@ -80,7 +84,6 @@ protected: */ class TabletButtonProxy : public QObject { Q_OBJECT - Q_PROPERTY(QString imageUrl READ getImageUrl WRITE setImageUrl) public: TabletButtonProxy(const QVariantMap& properties); @@ -90,16 +93,19 @@ public: */ Q_INVOKABLE void setInitRequestHandler(const QScriptValue& handler); - QString getImageUrl() const; - void setImageUrl(QString imageUrl); + const QVariantMap& getProperties() const { return _properties; } + +public slots: + void clickedSlot() { emit clicked(); } signals: /**jsdoc * Signaled when this button has been clicked on by the user. - * @function TabletButtonProxy#onClick + * @function TabletButtonProxy#clicked * @returns {Signal} */ - void onClick(); + void clicked(); + protected: mutable std::mutex _propertiesMutex; QVariantMap _properties; diff --git a/scripts/system/help.js b/scripts/system/help.js index e79ed0444c..a577688032 100644 --- a/scripts/system/help.js +++ b/scripts/system/help.js @@ -13,20 +13,14 @@ (function() { // BEGIN LOCAL_SCOPE - var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); - var buttonName = "help"; // matching location reserved in Desktop.qml - var button = toolBar.addButton({ - objectName: buttonName, - imageURL: Script.resolvePath("assets/images/tools/help.svg"), - visible: true, - hoverState: 2, - defaultState: 1, - buttonState: 1, - alpha: 0.9 + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var button = tablet.addButton({ + //icon: "help.svg", + color: "#ff6f6f", + text: "HELP" }); // TODO: make button state reflect whether the window is opened or closed (independently from us). - function onClicked(){ Menu.triggerOption('Help...') } @@ -34,7 +28,7 @@ button.clicked.connect(onClicked); Script.scriptEnding.connect(function () { - toolBar.removeButton(buttonName); + tablet.removeButton(buttonName); button.clicked.disconnect(onClicked); });