mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Whitelist functionality for tablet apps
This commit is contained in:
parent
ff36cbf45f
commit
d162e1cff6
28 changed files with 284 additions and 218 deletions
18
interface/resources/qml/OverlayWindowTest.qml
Normal file
18
interface/resources/qml/OverlayWindowTest.qml
Normal file
|
@ -0,0 +1,18 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
Rectangle {
|
||||
width: 100
|
||||
height: 100
|
||||
color: "white"
|
||||
Rectangle {
|
||||
width: 10
|
||||
height: 10
|
||||
color: "red"
|
||||
}
|
||||
|
||||
Label {
|
||||
text: OverlayWindowTestString
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@ Windows.Window {
|
|||
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
|
||||
destroyOnCloseButton: false
|
||||
property var source;
|
||||
property var component;
|
||||
property var dynamicContent;
|
||||
|
||||
// Keyboard control properties in case needed by QML content.
|
||||
|
@ -35,28 +34,9 @@ Windows.Window {
|
|||
dynamicContent.destroy();
|
||||
dynamicContent = null;
|
||||
}
|
||||
component = Qt.createComponent(source);
|
||||
console.log("Created component " + component + " from source " + source);
|
||||
}
|
||||
|
||||
onComponentChanged: {
|
||||
console.log("Component changed to " + component)
|
||||
populate();
|
||||
}
|
||||
|
||||
function populate() {
|
||||
console.log("Populate called: dynamicContent " + dynamicContent + " component " + component);
|
||||
if (!dynamicContent && component) {
|
||||
if (component.status == Component.Error) {
|
||||
console.log("Error loading component:", component.errorString());
|
||||
} else if (component.status == Component.Ready) {
|
||||
console.log("Building dynamic content");
|
||||
dynamicContent = component.createObject(contentHolder);
|
||||
} else {
|
||||
console.log("Component not yet ready, connecting to status change");
|
||||
component.statusChanged.connect(populate);
|
||||
}
|
||||
}
|
||||
QmlSurface.load(source, contentHolder, function(newObject) {
|
||||
dynamicContent = newObject;
|
||||
});
|
||||
}
|
||||
|
||||
// Handle message traffic from the script that launched us to the loaded QML
|
||||
|
|
|
@ -2,6 +2,7 @@ import QtQuick 2.5
|
|||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import "."
|
||||
import "../../styles-uit"
|
||||
import "../audio" as HifiAudio
|
||||
|
||||
|
@ -12,6 +13,31 @@ Item {
|
|||
property int columnIndex: 0
|
||||
property int count: (flowMain.children.length - 1)
|
||||
|
||||
Component {
|
||||
id: buttonComponent
|
||||
TabletButton { }
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
tablet.populateButtons();
|
||||
}
|
||||
|
||||
function createClickedHandler(proxy) {
|
||||
return function() { proxy.clicked(); }
|
||||
}
|
||||
|
||||
function populateButtons() {
|
||||
var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
var buttons = tabletProxy.getButtons();
|
||||
for (var i = 0; i < buttons.length; i++) {
|
||||
var proxy = buttons[i];
|
||||
var button = tablet.addButtonProxy(proxy.getProperties());
|
||||
button.clicked.connect(createClickedHandler(proxy));
|
||||
proxy.setQmlButton(button);
|
||||
}
|
||||
sortButtons();
|
||||
}
|
||||
|
||||
// used to look up a button by its uuid
|
||||
function findButtonIndex(uuid) {
|
||||
if (!uuid) {
|
||||
|
@ -47,9 +73,7 @@ Item {
|
|||
|
||||
// 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);
|
||||
|
||||
var button = buttonComponent.createObject(flowMain);
|
||||
// copy all properites to button
|
||||
var keys = Object.keys(properties).forEach(function (key) {
|
||||
button[key] = properties[key];
|
||||
|
@ -62,8 +86,6 @@ Item {
|
|||
button.tabletRoot = parent.parent;
|
||||
}
|
||||
|
||||
sortButtons();
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
|
@ -83,11 +105,8 @@ Item {
|
|||
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: 0
|
||||
left: parent.left
|
||||
leftMargin: 0
|
||||
right: parent.right
|
||||
rightMargin: 0
|
||||
}
|
||||
|
||||
gradient: Gradient {
|
||||
|
|
|
@ -68,18 +68,17 @@ Item {
|
|||
|
||||
function loadSource(url) {
|
||||
tabletApps.clear();
|
||||
loader.source = ""; // make sure we load the qml fresh each time.
|
||||
loader.source = url;
|
||||
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
||||
loader.load(url)
|
||||
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
||||
}
|
||||
|
||||
function loadQMLOnTop(url) {
|
||||
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
||||
loader.source = "";
|
||||
loader.source = tabletApps.get(currentApp).appUrl;
|
||||
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
||||
loader.item.gotoPreviousApp = true;
|
||||
}
|
||||
loader.load(tabletApps.get(currentApp).appUrl, function(){
|
||||
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
||||
loader.item.gotoPreviousApp = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function loadWebOnTop(url, injectJavaScriptUrl) {
|
||||
|
@ -92,13 +91,11 @@ Item {
|
|||
}
|
||||
|
||||
function loadWebBase() {
|
||||
loader.source = "";
|
||||
loader.source = "TabletWebView.qml";
|
||||
loader.load("hifi/tablet/TabletWebView.qml");
|
||||
}
|
||||
|
||||
function loadTabletWebBase() {
|
||||
loader.source = "";
|
||||
loader.source = "./BlocksWebView.qml";
|
||||
loader.load("hifi/tablet/BlocksWebView.qml");
|
||||
}
|
||||
|
||||
function returnToPreviousApp() {
|
||||
|
@ -110,7 +107,7 @@ Item {
|
|||
loadSource("TabletWebView.qml");
|
||||
loadWebUrl(webUrl, scriptUrl);
|
||||
} else {
|
||||
loader.source = tabletApps.get(currentApp).appUrl;
|
||||
loader.load(tabletApps.get(currentApp).appUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,47 +170,72 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
objectName: "loader"
|
||||
asynchronous: false
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
// Hook up callback for clara.io download from the marketplace.
|
||||
Connections {
|
||||
id: eventBridgeConnection
|
||||
target: eventBridge
|
||||
onWebEventReceived: {
|
||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||
}
|
||||
if (loader.item.hasOwnProperty("setRootMenu")) {
|
||||
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||
}
|
||||
loader.item.forceActiveFocus();
|
||||
|
||||
if (openModal) {
|
||||
openModal.canceled();
|
||||
openModal.destroy();
|
||||
openModal = null;
|
||||
}
|
||||
|
||||
if (openBrowser) {
|
||||
openBrowser.destroy();
|
||||
openBrowser = null;
|
||||
// Hook up callback for clara.io download from the marketplace.
|
||||
Connections {
|
||||
id: eventBridgeConnection
|
||||
target: eventBridge
|
||||
onWebEventReceived: {
|
||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: loader
|
||||
objectName: "loader";
|
||||
anchors.fill: parent;
|
||||
property string source: "";
|
||||
property var item: null;
|
||||
signal loaded;
|
||||
|
||||
onWidthChanged: {
|
||||
if (loader.item) {
|
||||
loader.item.width = loader.width;
|
||||
}
|
||||
}
|
||||
|
||||
onHeightChanged: {
|
||||
if (loader.item) {
|
||||
loader.item.height = loader.height;
|
||||
}
|
||||
}
|
||||
|
||||
function load(newSource, callback) {
|
||||
loader.source = newSource;
|
||||
loader.item = null;
|
||||
QmlSurface.load(newSource, loader, function(newItem) {
|
||||
loader.item = newItem;
|
||||
loader.item.width = loader.width;
|
||||
loader.item.height = loader.height;
|
||||
loader.loaded();
|
||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||
}
|
||||
if (loader.item.hasOwnProperty("setRootMenu")) {
|
||||
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||
}
|
||||
loader.item.forceActiveFocus();
|
||||
|
||||
if (openModal) {
|
||||
openModal.canceled();
|
||||
openModal.destroy();
|
||||
openModal = null;
|
||||
}
|
||||
|
||||
if (openBrowser) {
|
||||
openBrowser.destroy();
|
||||
openBrowser = null;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
console.log("QQQ done calling QmlSurface.load")
|
||||
}
|
||||
}
|
||||
|
||||
width: 480
|
||||
height: 706
|
||||
|
||||
|
|
|
@ -2214,6 +2214,16 @@ extern void setupPreferences();
|
|||
void Application::initializeUi() {
|
||||
// Make sure all QML surfaces share the main thread GL context
|
||||
OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext());
|
||||
OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "qrc:///qml/OverlayWindowTest.qml" },
|
||||
[](QQmlContext* context) {
|
||||
qDebug() << "Whitelist OverlayWindow worked";
|
||||
context->setContextProperty("OverlayWindowTestString", "TestWorked");
|
||||
});
|
||||
OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "qrc:///qml/hifi/audio/Audio.qml" },
|
||||
[](QQmlContext* context) {
|
||||
qDebug() << "QQQ" << __FUNCTION__ << "Whitelist Audio worked";
|
||||
});
|
||||
|
||||
|
||||
AddressBarDialog::registerType();
|
||||
ErrorDialog::registerType();
|
||||
|
@ -2230,10 +2240,9 @@ void Application::initializeUi() {
|
|||
auto surfaceContext = offscreenUi->getSurfaceContext();
|
||||
|
||||
offscreenUi->setProxyWindow(_window->windowHandle());
|
||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
|
||||
// support the window management and scripting proxies for VR use
|
||||
offscreenUi->createDesktop(QString("qrc:///qml/hifi/Desktop.qml"));
|
||||
offscreenUi->createDesktop(QString("hifi/Desktop.qml"));
|
||||
|
||||
// FIXME either expose so that dialogs can set this themselves or
|
||||
// do better detection in the offscreen UI of what has focus
|
||||
|
@ -7194,13 +7203,17 @@ void Application::updateDisplayMode() {
|
|||
}
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
auto desktop = offscreenUi->getDesktop();
|
||||
|
||||
// Make the switch atomic from the perspective of other threads
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_displayPluginLock);
|
||||
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
|
||||
bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
|
||||
offscreenUi->getDesktop()->setProperty("repositionLocked", true);
|
||||
bool wasRepositionLocked = false;
|
||||
if (desktop) {
|
||||
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
|
||||
wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
|
||||
offscreenUi->getDesktop()->setProperty("repositionLocked", true);
|
||||
}
|
||||
|
||||
if (_displayPlugin) {
|
||||
disconnect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
|
||||
|
@ -7246,7 +7259,6 @@ void Application::updateDisplayMode() {
|
|||
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
|
||||
_displayPlugin = newDisplayPlugin;
|
||||
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection);
|
||||
auto desktop = offscreenUi->getDesktop();
|
||||
if (desktop) {
|
||||
desktop->setProperty("repositionLocked", wasRepositionLocked);
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ Menu::Menu() {
|
|||
auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J);
|
||||
connect(action, &QAction::triggered, [] {
|
||||
static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml");
|
||||
static const QUrl tabletUrl("../../hifi/dialogs/TabletRunningScripts.qml");
|
||||
static const QUrl tabletUrl("hifi/dialogs/TabletRunningScripts.qml");
|
||||
static const QString name("RunningScripts");
|
||||
qApp->showDialog(widgetUrl, tabletUrl, name);
|
||||
});
|
||||
|
@ -338,7 +338,7 @@ Menu::Menu() {
|
|||
connect(action, &QAction::triggered, [] {
|
||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
tablet->loadQMLSource("ControllerSettings.qml");
|
||||
tablet->loadQMLSource("hifi/tablet/ControllerSettings.qml");
|
||||
|
||||
if (!hmd->getShouldShowTablet()) {
|
||||
hmd->toggleShouldShowTablet();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//
|
||||
//
|
||||
// WalletScriptingInterface.cpp
|
||||
// interface/src/scripting
|
||||
//
|
||||
|
@ -23,7 +23,7 @@ void WalletScriptingInterface::refreshWalletStatus() {
|
|||
wallet->getWalletStatus();
|
||||
}
|
||||
|
||||
static const QString CHECKOUT_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/checkout/Checkout.qml";
|
||||
static const QString CHECKOUT_QML_PATH = "hifi/commerce/checkout/Checkout.qml";
|
||||
void WalletScriptingInterface::buy(const QString& name, const QString& id, const int& price, const QString& href) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "buy", Q_ARG(const QString&, name), Q_ARG(const QString&, id), Q_ARG(const int&, price), Q_ARG(const QString&, href));
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
|
||||
static const QVariant TABLET_ADDRESS_DIALOG = "TabletAddressDialog.qml";
|
||||
static const QVariant TABLET_ADDRESS_DIALOG = "hifi/tablet/TabletAddressDialog.qml";
|
||||
template<typename T>
|
||||
void DialogsManager::maybeCreateDialog(QPointer<T>& member) {
|
||||
if (!member) {
|
||||
|
@ -91,7 +91,7 @@ void DialogsManager::setDomainConnectionFailureVisibility(bool visible) {
|
|||
ConnectionFailureDialog::hide();
|
||||
}
|
||||
} else {
|
||||
static const QUrl url("../../dialogs/TabletConnectionFailureDialog.qml");
|
||||
static const QUrl url("dialogs/TabletConnectionFailureDialog.qml");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
if (visible) {
|
||||
tablet->initialScreen(url);
|
||||
|
|
|
@ -46,7 +46,7 @@ void LoginDialog::showWithSelection()
|
|||
if (tablet->getToolbarMode()) {
|
||||
LoginDialog::show();
|
||||
} else {
|
||||
static const QUrl url("../../dialogs/TabletLoginDialog.qml");
|
||||
static const QUrl url("dialogs/TabletLoginDialog.qml");
|
||||
tablet->initialScreen(url);
|
||||
if (!hmd->getShouldShowTablet()) {
|
||||
hmd->openTablet();
|
||||
|
|
|
@ -264,7 +264,7 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI
|
|||
}
|
||||
}
|
||||
|
||||
static const QString INSPECTION_CERTIFICATE_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
||||
static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
||||
void ContextOverlayInterface::openInspectionCertificate() {
|
||||
// lets open the tablet to the inspection certificate QML
|
||||
if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
using namespace render;
|
||||
using namespace render::entities;
|
||||
|
||||
static const QString WEB_ENTITY_QML = "controls/WebEntityView.qml";
|
||||
|
||||
const float METERS_TO_INCHES = 39.3701f;
|
||||
static uint32_t _currentWebCount{ 0 };
|
||||
// Don't allow more than 100 concurrent web views
|
||||
|
@ -218,6 +220,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
|
|||
};
|
||||
|
||||
{
|
||||
// FIXME use the surface cache instead of explicit creation
|
||||
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
|
||||
_webSurface->create();
|
||||
}
|
||||
|
@ -289,7 +292,6 @@ void WebEntityRenderer::loadSourceURL() {
|
|||
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
|
||||
_lastSourceUrl.toLower().endsWith(".htm") || _lastSourceUrl.toLower().endsWith(".html")) {
|
||||
_contentType = htmlContent;
|
||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "qml/controls/"));
|
||||
|
||||
// We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS.
|
||||
if (sourceUrl.host().endsWith("youtube.com", Qt::CaseInsensitive)) {
|
||||
|
@ -298,12 +300,11 @@ void WebEntityRenderer::loadSourceURL() {
|
|||
_webSurface->setMaxFps(DEFAULT_MAX_FPS);
|
||||
}
|
||||
|
||||
_webSurface->load("WebEntityView.qml", [this](QQmlContext* context, QObject* item) {
|
||||
_webSurface->load("controls/WebEntityView.qml", [this](QQmlContext* context, QObject* item) {
|
||||
item->setProperty("url", _lastSourceUrl);
|
||||
});
|
||||
} else {
|
||||
_contentType = qmlContent;
|
||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath()));
|
||||
_webSurface->load(_lastSourceUrl);
|
||||
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
|
|
|
@ -62,7 +62,7 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) {
|
|||
|
||||
QUrl url { properties[SOURCE_PROPERTY].toString() };
|
||||
if (url.scheme() != "http" && url.scheme() != "https" && url.scheme() != "file" && url.scheme() != "about" &&
|
||||
url.scheme() != "atp") {
|
||||
url.scheme() != "atp" && url.scheme() != "qrc") {
|
||||
properties[SOURCE_PROPERTY] = QUrl::fromLocalFile(url.toString()).toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "types/HFWebEngineProfile.h"
|
||||
#include "types/SoundEffect.h"
|
||||
|
||||
#include "TabletScriptingInterface.h"
|
||||
#include "Logging.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml")
|
||||
|
@ -98,7 +99,7 @@ void OffscreenQmlSurface::addWhitelistContextHandler(const std::initializer_list
|
|||
}
|
||||
|
||||
|
||||
QmlContextCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QObject*) {};
|
||||
QmlContextObjectCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QQuickItem*) {};
|
||||
|
||||
struct TextureSet {
|
||||
// The number of surfaces with this size
|
||||
|
@ -586,10 +587,11 @@ void OffscreenQmlSurface::create() {
|
|||
auto qmlEngine = acquireEngine(_quickWindow);
|
||||
|
||||
_qmlContext = new QQmlContext(qmlEngine->rootContext());
|
||||
|
||||
_qmlContext->setBaseUrl(QUrl{ "qrc:///qml/" });
|
||||
_qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
|
||||
_qmlContext->setContextProperty("eventBridge", this);
|
||||
_qmlContext->setContextProperty("webEntity", this);
|
||||
_qmlContext->setContextProperty("QmlSurface", this);
|
||||
|
||||
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||
|
@ -684,55 +686,69 @@ QQuickItem* OffscreenQmlSurface::getRootItem() {
|
|||
return _rootItem;
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
|
||||
_qmlContext->setBaseUrl(baseUrl);
|
||||
QQmlContext* OffscreenQmlSurface::contextForUrl(const QUrl& qmlSource, bool forceNewContext) {
|
||||
// Get any whitelist functionality
|
||||
QList<QmlContextCallback> callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource);
|
||||
// If we have whitelisted content, we must load a new context
|
||||
forceNewContext |= !callbacks.empty();
|
||||
|
||||
QQmlContext* targetContext = _qmlContext;
|
||||
if (_rootItem && forceNewContext) {
|
||||
targetContext = new QQmlContext(targetContext);
|
||||
}
|
||||
|
||||
for (const auto& callback : callbacks) {
|
||||
callback(targetContext);
|
||||
}
|
||||
|
||||
return targetContext;
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback) {
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) {
|
||||
loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) {
|
||||
QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem));
|
||||
});
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback) {
|
||||
loadInternal(qmlSource, createNewContext, nullptr, onQmlLoadedCallback);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::loadInternal(const QUrl& qmlSource, bool createNewContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback) {
|
||||
qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << qmlSource;
|
||||
if (QThread::currentThread() != thread()) {
|
||||
qCWarning(uiLogging) << "Called load on a non-surface thread";
|
||||
}
|
||||
// Synchronous loading may take a while; restart the deadlock timer
|
||||
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
|
||||
|
||||
// Get any whitelist functionality
|
||||
QList<QmlContextCallback> callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource);
|
||||
// If we have whitelisted content, we must load a new context
|
||||
createNewContext |= !callbacks.empty();
|
||||
callbacks.push_back(onQmlLoadedCallback);
|
||||
|
||||
QQmlContext* targetContext = _qmlContext;
|
||||
if (_rootItem && createNewContext) {
|
||||
targetContext = new QQmlContext(targetContext);
|
||||
}
|
||||
|
||||
|
||||
// FIXME eliminate loading of relative file paths for QML
|
||||
QUrl finalQmlSource = qmlSource;
|
||||
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
|
||||
finalQmlSource = _qmlContext->resolvedUrl(qmlSource);
|
||||
qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << "resolved to " << finalQmlSource;
|
||||
}
|
||||
|
||||
auto targetContext = contextForUrl(finalQmlSource, createNewContext);
|
||||
auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous);
|
||||
if (qmlComponent->isLoading()) {
|
||||
connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) {
|
||||
finishQmlLoad(qmlComponent, targetContext, callbacks);
|
||||
finishQmlLoad(qmlComponent, targetContext, parent, onQmlLoadedCallback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
finishQmlLoad(qmlComponent, targetContext, callbacks);
|
||||
finishQmlLoad(qmlComponent, targetContext, parent, onQmlLoadedCallback);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) {
|
||||
void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback) {
|
||||
load(qmlSource, true, onQmlLoadedCallback);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) {
|
||||
void OffscreenQmlSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback) {
|
||||
load(qmlSource, false, onQmlLoadedCallback);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback) {
|
||||
void OffscreenQmlSurface::load(const QString& qmlSourceFile, const QmlContextObjectCallback& onQmlLoadedCallback) {
|
||||
return load(QUrl(qmlSourceFile), onQmlLoadedCallback);
|
||||
}
|
||||
|
||||
|
@ -740,7 +756,8 @@ void OffscreenQmlSurface::clearCache() {
|
|||
_qmlContext->engine()->clearComponentCache();
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList<QmlContextCallback>& callbacks) {
|
||||
|
||||
void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, QQuickItem* parent, const QmlContextObjectCallback& callback) {
|
||||
disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0);
|
||||
if (qmlComponent->isError()) {
|
||||
for (const auto& error : qmlComponent->errors()) {
|
||||
|
@ -762,6 +779,22 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext
|
|||
return;
|
||||
}
|
||||
|
||||
if (!newObject) {
|
||||
if (!_rootItem) {
|
||||
qFatal("Could not load object as root item");
|
||||
return;
|
||||
}
|
||||
qCWarning(uiLogging) << "Unable to load QML item";
|
||||
return;
|
||||
}
|
||||
|
||||
QObject* eventBridge = qmlContext->contextProperty("eventBridge").value<QObject*>();
|
||||
if (qmlContext != _qmlContext && eventBridge && eventBridge != this) {
|
||||
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||
qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(eventBridge, qmlContext));
|
||||
}
|
||||
|
||||
qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
|
||||
// All quick items should be focusable
|
||||
|
@ -772,37 +805,26 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext
|
|||
newItem->setFlag(QQuickItem::ItemIsFocusScope, true);
|
||||
}
|
||||
|
||||
|
||||
// Make sure we will call callback for this codepath
|
||||
// Call this before qmlComponent->completeCreate() otherwise ghost window appears
|
||||
if (newItem && _rootItem) {
|
||||
for (const auto& callback : callbacks) {
|
||||
callback(qmlContext, newObject);
|
||||
}
|
||||
}
|
||||
// If we already have a root, just set a couple of flags and the ancestry
|
||||
if (_rootItem) {
|
||||
callback(qmlContext, newItem);
|
||||
|
||||
QObject* eventBridge = qmlContext->contextProperty("eventBridge").value<QObject*>();
|
||||
if (qmlContext != _qmlContext && eventBridge && eventBridge != this) {
|
||||
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||
qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(eventBridge, qmlContext));
|
||||
if (!parent) {
|
||||
parent = _rootItem;
|
||||
}
|
||||
// Allow child windows to be destroyed from JS
|
||||
QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership);
|
||||
newObject->setParent(parent);
|
||||
newItem->setParentItem(parent);
|
||||
}
|
||||
|
||||
qmlComponent->completeCreate();
|
||||
qmlComponent->deleteLater();
|
||||
|
||||
// If we already have a root, just set a couple of flags and the ancestry
|
||||
if (newItem && _rootItem) {
|
||||
// Allow child windows to be destroyed from JS
|
||||
QQmlEngine::setObjectOwnership(newObject, QQmlEngine::JavaScriptOwnership);
|
||||
newObject->setParent(_rootItem);
|
||||
if (newItem) {
|
||||
newItem->setParentItem(_rootItem);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!newItem) {
|
||||
qFatal("Could not load object as root item");
|
||||
if (_rootItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -813,10 +835,16 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext
|
|||
_rootItem->setParentItem(_quickWindow->contentItem());
|
||||
_rootItem->setSize(_quickWindow->renderTargetSize());
|
||||
|
||||
// Call this callback after rootitem is set, otherwise VrMenu wont work
|
||||
for (const auto& callback : callbacks) {
|
||||
callback(qmlContext, newObject);
|
||||
if (_rootItem->objectName() == "tabletRoot") {
|
||||
_qmlContext->setContextProperty("tabletRoot", QVariant::fromValue(_rootItem));
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", this);
|
||||
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
|
||||
_qmlContext->engine()->setObjectOwnership(tablet, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
// Call this callback after rootitem is set, otherwise VrMenu wont work
|
||||
callback(qmlContext, newItem);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::updateQuick() {
|
||||
|
|
|
@ -30,12 +30,14 @@ class QQmlContext;
|
|||
class QQmlComponent;
|
||||
class QQuickWindow;
|
||||
class QQuickItem;
|
||||
class QJSValue;
|
||||
|
||||
// GPU resources are typically buffered for one copy being used by the renderer,
|
||||
// one copy in flight, and one copy being used by the receiver
|
||||
#define GPU_RESOURCE_BUFFER_SIZE 3
|
||||
|
||||
using QmlContextCallback = std::function<void(QQmlContext*, QObject*)>;
|
||||
using QmlContextCallback = std::function<void(QQmlContext*)>;
|
||||
using QmlContextObjectCallback = std::function<void(QQmlContext*, QQuickItem*)>;
|
||||
|
||||
class OffscreenQmlSurface : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -43,7 +45,7 @@ class OffscreenQmlSurface : public QObject {
|
|||
public:
|
||||
static void setSharedContext(QOpenGLContext* context);
|
||||
|
||||
static QmlContextCallback DEFAULT_CONTEXT_CALLBACK;
|
||||
static QmlContextObjectCallback DEFAULT_CONTEXT_CALLBACK;
|
||||
static void addWhitelistContextHandler(const std::initializer_list<QUrl>& urls, const QmlContextCallback& callback);
|
||||
static void addWhitelistContextHandler(const QUrl& url, const QmlContextCallback& callback) { addWhitelistContextHandler({ { url } }, callback); };
|
||||
|
||||
|
@ -56,10 +58,15 @@ public:
|
|||
void resize(const QSize& size, bool forceResize = false);
|
||||
QSize size() const;
|
||||
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
// Usable from QML code as QmlSurface.load(url, parent, function(newItem){ ... })
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback);
|
||||
|
||||
// For C++ use
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextObjectCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK);
|
||||
|
||||
void clearCache();
|
||||
void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; }
|
||||
// Optional values for event handling
|
||||
|
@ -73,7 +80,6 @@ public:
|
|||
void resume();
|
||||
bool isPaused() const;
|
||||
|
||||
void setBaseUrl(const QUrl& baseUrl);
|
||||
QQuickItem* getRootItem();
|
||||
QQuickWindow* getWindow();
|
||||
QObject* getEventHandler();
|
||||
|
@ -124,13 +130,13 @@ protected:
|
|||
private:
|
||||
static QOpenGLContext* getSharedContext();
|
||||
|
||||
void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList<QmlContextCallback>& callbacks);
|
||||
QQmlContext* contextForUrl(const QUrl& url, bool forceNewContext = false);
|
||||
void loadInternal(const QUrl& qmlSource, bool createNewContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback);
|
||||
void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, QQuickItem* parent, const QmlContextObjectCallback& onQmlLoadedCallback);
|
||||
QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
|
||||
void setupFbo();
|
||||
bool allowNewFrame(uint8_t fps);
|
||||
void render();
|
||||
void cleanup();
|
||||
QJsonObject getGLContextData();
|
||||
|
||||
private slots:
|
||||
void updateQuick();
|
||||
|
|
|
@ -45,7 +45,6 @@ void OffscreenQmlSurfaceCache::release(const QString& rootSource, const QSharedP
|
|||
QSharedPointer<OffscreenQmlSurface> OffscreenQmlSurfaceCache::buildSurface(const QString& rootSource) {
|
||||
auto surface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface());
|
||||
surface->create();
|
||||
surface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||
surface->load(rootSource);
|
||||
surface->resize(QSize(100, 100));
|
||||
return surface;
|
||||
|
|
|
@ -210,9 +210,9 @@ QObject* TabletScriptingInterface::getFlags() {
|
|||
// TabletProxy
|
||||
//
|
||||
|
||||
static const char* TABLET_SOURCE_URL = "Tablet.qml";
|
||||
static const char* WEB_VIEW_SOURCE_URL = "TabletWebView.qml";
|
||||
static const char* VRMENU_SOURCE_URL = "TabletMenu.qml";
|
||||
static const char* TABLET_SOURCE_URL = "hifi/tablet/Tablet.qml";
|
||||
static const char* WEB_VIEW_SOURCE_URL = "hifi/tablet/TabletWebView.qml";
|
||||
static const char* VRMENU_SOURCE_URL = "hifi/tablet/TabletMenu.qml";
|
||||
|
||||
class TabletRootWindow : public QmlWindowClass {
|
||||
virtual QString qmlSource() const override { return "hifi/tablet/WindowRoot.qml"; }
|
||||
|
@ -232,6 +232,15 @@ TabletProxy::~TabletProxy() {
|
|||
disconnect(this, &TabletProxy::tabletShownChanged, this, &TabletProxy::onTabletShown);
|
||||
}
|
||||
|
||||
QVariant TabletProxy::getButtons() {
|
||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||
QVariantList result;
|
||||
for (const auto& button : _tabletButtonProxies) {
|
||||
result.push_back(QVariant::fromValue(button.data()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void TabletProxy::setToolbarMode(bool toolbarMode) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setToolbarMode", Q_ARG(bool, toolbarMode));
|
||||
|
@ -247,7 +256,6 @@ void TabletProxy::setToolbarMode(bool toolbarMode) {
|
|||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
|
||||
if (toolbarMode) {
|
||||
removeButtonsFromHomeScreen();
|
||||
addButtonsToToolbar();
|
||||
|
||||
// create new desktop window
|
||||
|
@ -267,7 +275,7 @@ void TabletProxy::setToolbarMode(bool toolbarMode) {
|
|||
removeButtonsFromToolbar();
|
||||
|
||||
if (_currentPathLoaded == TABLET_SOURCE_URL) {
|
||||
addButtonsToHomeScreen();
|
||||
// Tablet QML now pulls buttons from Tablet proxy
|
||||
} else {
|
||||
loadHomeScreen(true);
|
||||
}
|
||||
|
@ -284,18 +292,20 @@ void TabletProxy::setToolbarMode(bool toolbarMode) {
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy* buttonProxy) {
|
||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||
if (buttonProxy == NULL){
|
||||
qCCritical(uiLogging) << "TabletScriptingInterface addButtonProxyToQmlTablet buttonProxy is NULL";
|
||||
qCCritical(uiLogging) << __FUNCTION__ << "buttonProxy is NULL";
|
||||
return;
|
||||
}
|
||||
|
||||
QVariant resultVar;
|
||||
qCDebug(uiLogging) << "QQQ" << __FUNCTION__ << "adding button " << buttonProxy;
|
||||
bool hasResult = QMetaObject::invokeMethod(qmlTablet, "addButtonProxy", Qt::DirectConnection,
|
||||
Q_RETURN_ARG(QVariant, resultVar), Q_ARG(QVariant, buttonProxy->getProperties()));
|
||||
if (!hasResult) {
|
||||
qCWarning(uiLogging) << "TabletScriptingInterface addButtonProxyToQmlTablet has no result";
|
||||
qCWarning(uiLogging) << __FUNCTION__ << " has no result";
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -307,6 +317,8 @@ static void addButtonProxyToQmlTablet(QQuickItem* qmlTablet, TabletButtonProxy*
|
|||
QObject::connect(qmlButton, SIGNAL(clicked()), buttonProxy, SLOT(clickedSlot()));
|
||||
buttonProxy->setQmlButton(qobject_cast<QQuickItem*>(qmlButton));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static QString getUsername() {
|
||||
QString username = "Unknown user";
|
||||
|
@ -362,7 +374,7 @@ void TabletProxy::onTabletShown() {
|
|||
static_cast<TabletScriptingInterface*>(parent())->playSound(TabletScriptingInterface::TabletOpen);
|
||||
if (_showRunningScripts) {
|
||||
_showRunningScripts = false;
|
||||
pushOntoStack("../../hifi/dialogs/TabletRunningScripts.qml");
|
||||
pushOntoStack("hifi/dialogs/TabletRunningScripts.qml");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -396,9 +408,6 @@ void TabletProxy::setQmlTabletRoot(OffscreenQmlSurface* qmlOffscreenSurface) {
|
|||
});
|
||||
|
||||
if (_toolbarMode) {
|
||||
// if someone creates the tablet in toolbar mode, make sure to display the home screen on the tablet.
|
||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()));
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL)));
|
||||
}
|
||||
|
||||
|
@ -427,7 +436,6 @@ void TabletProxy::setQmlTabletRoot(OffscreenQmlSurface* qmlOffscreenSurface) {
|
|||
QMetaObject::invokeMethod(_qmlTabletRoot, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||
}
|
||||
} else {
|
||||
removeButtonsFromHomeScreen();
|
||||
_state = State::Uninitialized;
|
||||
emit screenChanged(QVariant("Closed"), QVariant(""));
|
||||
_currentPathLoaded = "";
|
||||
|
@ -456,7 +464,6 @@ void TabletProxy::gotoMenuScreen(const QString& submenu) {
|
|||
}
|
||||
|
||||
if (root) {
|
||||
removeButtonsFromHomeScreen();
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QObject* menu = offscreenUi->getRootMenu();
|
||||
QMetaObject::invokeMethod(root, "setMenuProperties", Q_ARG(QVariant, QVariant::fromValue(menu)), Q_ARG(const QVariant&, QVariant(submenu)));
|
||||
|
@ -530,7 +537,6 @@ void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) {
|
|||
}
|
||||
|
||||
if (root) {
|
||||
removeButtonsFromHomeScreen(); //works only in Tablet
|
||||
QMetaObject::invokeMethod(root, "loadSource", Q_ARG(const QVariant&, path));
|
||||
_state = State::QML;
|
||||
if (path != _currentPathLoaded) {
|
||||
|
@ -612,8 +618,6 @@ void TabletProxy::loadHomeScreen(bool forceOntoHomeScreen) {
|
|||
|
||||
if ((_state != State::Home && _state != State::Uninitialized) || forceOntoHomeScreen) {
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||
QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()));
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(TABLET_SOURCE_URL)));
|
||||
QMetaObject::invokeMethod(_qmlTabletRoot, "playButtonClickSound");
|
||||
} else if (_toolbarMode && _desktopWindow) {
|
||||
|
@ -674,7 +678,6 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS
|
|||
}
|
||||
|
||||
if (root) {
|
||||
removeButtonsFromHomeScreen();
|
||||
if (loadOtherBase) {
|
||||
QMetaObject::invokeMethod(root, "loadTabletWebBase");
|
||||
} else {
|
||||
|
@ -701,12 +704,8 @@ TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) {
|
|||
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
|
||||
_tabletButtonProxies.push_back(tabletButtonProxy);
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
auto tablet = getQmlTablet();
|
||||
if (tablet) {
|
||||
addButtonProxyToQmlTablet(tablet, tabletButtonProxy.data());
|
||||
} else {
|
||||
qCCritical(uiLogging) << "Could not find tablet in TabletRoot.qml";
|
||||
}
|
||||
// Tablet now pulls buttons from the tablet proxy
|
||||
// FIXME emit a signal so that the tablet can refresh buttons if they change
|
||||
} else if (_toolbarMode) {
|
||||
auto toolbarProxy = DependencyManager::get<TabletScriptingInterface>()->getSystemToolbarProxy();
|
||||
if (toolbarProxy) {
|
||||
|
@ -791,31 +790,11 @@ void TabletProxy::sendToQml(const QVariant& msg) {
|
|||
}
|
||||
}
|
||||
|
||||
void TabletProxy::addButtonsToHomeScreen() {
|
||||
auto tablet = getQmlTablet();
|
||||
if (!tablet || _toolbarMode) {
|
||||
return;
|
||||
}
|
||||
for (auto& buttonProxy : _tabletButtonProxies) {
|
||||
addButtonProxyToQmlTablet(tablet, buttonProxy.data());
|
||||
}
|
||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("loader");
|
||||
QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen()));
|
||||
}
|
||||
|
||||
OffscreenQmlSurface* TabletProxy::getTabletSurface() {
|
||||
return _qmlOffscreenSurface;
|
||||
}
|
||||
|
||||
void TabletProxy::removeButtonsFromHomeScreen() {
|
||||
auto tablet = getQmlTablet();
|
||||
for (auto& buttonProxy : _tabletButtonProxies) {
|
||||
if (tablet) {
|
||||
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getProperties()));
|
||||
}
|
||||
buttonProxy->setQmlButton(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void TabletProxy::desktopWindowClosed() {
|
||||
gotoHomeScreen();
|
||||
|
|
|
@ -196,6 +196,8 @@ public:
|
|||
|
||||
Q_INVOKABLE bool isPathLoaded(const QVariant& path);
|
||||
|
||||
Q_INVOKABLE QVariant getButtons();
|
||||
|
||||
QQuickItem* getTabletRoot() const { return _qmlTabletRoot; }
|
||||
|
||||
OffscreenQmlSurface* getTabletSurface();
|
||||
|
@ -237,12 +239,10 @@ signals:
|
|||
void tabletShownChanged();
|
||||
|
||||
protected slots:
|
||||
void addButtonsToHomeScreen();
|
||||
void desktopWindowClosed();
|
||||
void emitWebEvent(const QVariant& msg);
|
||||
void onTabletShown();
|
||||
protected:
|
||||
void removeButtonsFromHomeScreen();
|
||||
void loadHomeScreen(bool forceOntoHomeScreen);
|
||||
void addButtonsToToolbar();
|
||||
void removeButtonsFromToolbar();
|
||||
|
@ -277,7 +277,9 @@ public:
|
|||
TabletButtonProxy(const QVariantMap& properties);
|
||||
~TabletButtonProxy();
|
||||
|
||||
void setQmlButton(QQuickItem* qmlButton);
|
||||
|
||||
Q_INVOKABLE void setQmlButton(QQuickItem* qmlButton);
|
||||
|
||||
void setToolbarButtonProxy(QObject* toolbarButtonProxy);
|
||||
|
||||
QUuid getUuid() const { return _uuid; }
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
tablet.gotoHomeScreen();
|
||||
onRecordingScreen = false;
|
||||
} else {
|
||||
tablet.loadQMLSource("InputRecorder.qml");
|
||||
tablet.loadQMLSource("hifi/tablet/InputRecorder.qml");
|
||||
onRecordingScreen = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
print("Launching web window");
|
||||
qmlWindow = new OverlayWindow({
|
||||
title: 'Test Qml',
|
||||
source: "https://s3.amazonaws.com/DreamingContent/qml/content.qml",
|
||||
source: "qrc:///qml/OverlayWindowTest.qml",
|
||||
height: 240,
|
||||
width: 320,
|
||||
toolWindow: false,
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
var TABLET_BUTTON_NAME = "AUDIO";
|
||||
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
|
||||
var AUDIO_QML_SOURCE = "../audio/Audio.qml";
|
||||
var AUDIO_QML_SOURCE = "hifi/audio/Audio.qml";
|
||||
|
||||
var MUTE_ICONS = {
|
||||
icon: "icons/tablet-icons/mic-mute-i.svg",
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
// Relevant Variables:
|
||||
// -WALLET_QML_SOURCE: The path to the Wallet QML
|
||||
// -onWalletScreen: true/false depending on whether we're looking at the app.
|
||||
var WALLET_QML_SOURCE = Script.resourcesPath() + "qml/hifi/commerce/wallet/Wallet.qml";
|
||||
var MARKETPLACE_PURCHASES_QML_PATH = Script.resourcesPath() + "qml/hifi/commerce/purchases/Purchases.qml";
|
||||
var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml";
|
||||
var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml";
|
||||
var onWalletScreen = false;
|
||||
function onButtonClicked() {
|
||||
if (!tablet) {
|
||||
|
|
|
@ -656,7 +656,7 @@ var toolBar = (function () {
|
|||
selectionDisplay.triggerMapping.disable();
|
||||
tablet.landscape = false;
|
||||
} else {
|
||||
tablet.loadQMLSource("Edit.qml", true);
|
||||
tablet.loadQMLSource("hifi/tablet/Edit.qml", true);
|
||||
UserActivityLogger.enabledEdit();
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
var buttonName = "Settings";
|
||||
var toolBar = null;
|
||||
var tablet = null;
|
||||
var settings = "TabletGeneralPreferences.qml"
|
||||
var settings = "hifi/tablet/TabletGeneralPreferences.qml"
|
||||
function onClicked(){
|
||||
if (tablet) {
|
||||
tablet.loadQMLSource(settings);
|
||||
|
|
|
@ -346,7 +346,7 @@
|
|||
Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled);
|
||||
break;
|
||||
case 'purchases_openGoTo':
|
||||
tablet.loadQMLSource("TabletAddressDialog.qml");
|
||||
tablet.loadQMLSource("hifi/tablet/TabletAddressDialog.qml");
|
||||
break;
|
||||
case 'purchases_itemCertificateClicked':
|
||||
setCertificateInfo("", message.itemCertificateId);
|
||||
|
|
|
@ -40,7 +40,7 @@ var HOVER_TEXTURES = {
|
|||
var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6};
|
||||
var SELECTED_COLOR = {red: 0xF3, green: 0x91, blue: 0x29};
|
||||
var HOVER_COLOR = {red: 0xD0, green: 0xD0, blue: 0xD0}; // almost white for now
|
||||
var PAL_QML_SOURCE = "../Pal.qml";
|
||||
var PAL_QML_SOURCE = "hifi/Pal.qml";
|
||||
var conserveResources = true;
|
||||
|
||||
Script.include("/~/system/libraries/controllers.js");
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
print('tablet-goto.js:', [].map.call(arguments, JSON.stringify));
|
||||
}
|
||||
|
||||
var gotoQmlSource = "TabletAddressDialog.qml";
|
||||
var gotoQmlSource = "hifi/tablet/TabletAddressDialog.qml";
|
||||
var buttonName = "GOTO";
|
||||
var onGotoScreen = false;
|
||||
var shouldActivateButton = false;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
if (onSkyboxChangerScreen) {
|
||||
tablet.gotoHomeScreen();
|
||||
} else {
|
||||
tablet.loadQMLSource("../SkyboxChanger.qml");
|
||||
tablet.loadQMLSource("hifi/SkyboxChanger.qml");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -390,7 +390,7 @@
|
|||
// Relevant Variables:
|
||||
// -SPECTATOR_CAMERA_QML_SOURCE: The path to the SpectatorCamera QML
|
||||
// -onSpectatorCameraScreen: true/false depending on whether we're looking at the spectator camera app.
|
||||
var SPECTATOR_CAMERA_QML_SOURCE = Script.resourcesPath() + "qml/hifi/SpectatorCamera.qml";
|
||||
var SPECTATOR_CAMERA_QML_SOURCE = "hifi/SpectatorCamera.qml";
|
||||
var onSpectatorCameraScreen = false;
|
||||
function onTabletButtonClicked() {
|
||||
if (!tablet) {
|
||||
|
|
Loading…
Reference in a new issue