//// OffscreenUi.cpp// interface/src/render-utils//// Created by Bradley Austin Davis on 2015-04-04// Copyright 2015 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 "OffscreenUi.h" #include <QtCore/QVariant>#include <QtGui/QGuiApplication>#include <QtQuick/QQuickWindow>#include <QtQml/QtQml> #include <shared/QtHelpers.h>#include <gl/GLHelpers.h> #include <AbstractUriHandler.h>#include <AccountManager.h>#include <DependencyManager.h> #include "ui/TabletScriptingInterface.h"#include "FileDialogHelper.h"#include "VrMenu.h" #include "ui/Logging.h"#include "ui/ToolbarScriptingInterface.h" #include <PointerManager.h>#include "MainWindow.h" /*@jsdoc * The <code>OffscreenFlags</code> API enables gamepad joystick navigation of UI. * * <p><em>This API currently has no effect and is not used.</em></p> * * @namespace OffscreenFlags * * @hifi-interface * @hifi-client-entity * @hifi-avatar * * @property {boolean} navigationFocused - <code>true</code> if UI has joystick navigation focus, <code>false</code> if it * doesn't. * @property {boolean} navigationFocusDisabled - <code>true</code> if UI joystick navigation focus is disabled, * <code>false</code> if it isn't. */ // Needs to match the constants in resources/qml/Global.jsclass OffscreenFlags : public QObject { Q_OBJECT Q_PROPERTY(bool navigationFocused READ isNavigationFocused WRITE setNavigationFocused NOTIFY navigationFocusedChanged) // Allow scripts that are doing their own navigation support to disable navigation focus (i.e. handControllerPointer.js) Q_PROPERTY(bool navigationFocusDisabled READ isNavigationFocusDisabled WRITE setNavigationFocusDisabled NOTIFY navigationFocusDisabledChanged) public: OffscreenFlags(QObject* parent = nullptr) : QObject(parent) {} bool isNavigationFocused() const { return _navigationFocused; } void setNavigationFocused(bool focused) { if (_navigationFocused != focused) { _navigationFocused = focused; emit navigationFocusedChanged(); } } bool isNavigationFocusDisabled() const { return _navigationFocusDisabled; } void setNavigationFocusDisabled(bool disabled) { if (_navigationFocusDisabled != disabled) { _navigationFocusDisabled = disabled; emit navigationFocusDisabledChanged(); } } signals: /*@jsdoc * Triggered when the value of the <code>navigationFocused</code> property changes. * @function OffscreenFlags.navigationFocusedChanged * @returns {Signal} */ void navigationFocusedChanged(); /*@jsdoc * Triggered when the value of the <code>navigationFocusDisabled</code> property changes. * @function OffscreenFlags.navigationFocusDisabledChanged * @returns {Signal} */ void navigationFocusDisabledChanged(); private: bool _navigationFocused { false }; bool _navigationFocusDisabled{ false };}; static OffscreenFlags* offscreenFlags { nullptr }; // This hack allows the QML UI to work with keys that are also bound as// shortcuts at the application level. However, it seems as though the// bound actions are still getting triggered. At least for backspace.// Not sure why.//// However, the problem may go away once we switch to the new menu system,// so I think it's OK for the time being.bool OffscreenUi::shouldSwallowShortcut(QEvent* event) { Q_ASSERT(event->type() == QEvent::ShortcutOverride); auto window = getWindow(); if (window) { QObject* focusObject = getWindow()->focusObject(); if (focusObject != getWindow() && focusObject != getRootItem()) { event->accept(); return true; } } return false;} static QTouchDevice _touchDevice;OffscreenUi::OffscreenUi() { static std::once_flag once; std::call_once(once, [&] { _touchDevice.setCapabilities(QTouchDevice::Position); _touchDevice.setType(QTouchDevice::TouchScreen); _touchDevice.setName("OffscreenUiTouchDevice"); _touchDevice.setMaximumTouchPoints(4); }); auto pointerManager = DependencyManager::get<PointerManager>(); connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &OffscreenUi::hoverBeginEvent); connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &OffscreenUi::handlePointerEvent); connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &OffscreenUi::hoverEndEvent); connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &OffscreenUi::handlePointerEvent); connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &OffscreenUi::handlePointerEvent); connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &OffscreenUi::handlePointerEvent); connect(pointerManager.data(), &PointerManager::scrollHUD, this, &OffscreenUi::handlePointerEvent);} void OffscreenUi::hoverBeginEvent(const PointerEvent& event) { OffscreenQmlSurface::hoverBeginEvent(event, _touchDevice);} void OffscreenUi::hoverEndEvent(const PointerEvent& event) { OffscreenQmlSurface::hoverEndEvent(event, _touchDevice);} void OffscreenUi::handlePointerEvent(const PointerEvent& event) { OffscreenQmlSurface::handlePointerEvent(event, _touchDevice);} QObject* OffscreenUi::getFlags() { return offscreenFlags;} void OffscreenUi::removeModalDialog(QObject* modal) { if (modal) { _modalDialogListeners.removeOne(modal); modal->deleteLater(); }} void OffscreenUi::onRootContextCreated(QQmlContext* qmlContext) { OffscreenQmlSurface::onRootContextCreated(qmlContext); qmlContext->setContextProperty("OffscreenUi", this); qmlContext->setContextProperty("offscreenFlags", offscreenFlags = new OffscreenFlags()); qmlContext->setContextProperty("fileDialogHelper", new FileDialogHelper());#ifdef DEBUG qmlContext->setContextProperty("DebugQML", QVariant(true));#else qmlContext->setContextProperty("DebugQML", QVariant(false));#endif } void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) { emit showDesktop(); QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name); // First load? if (!item) { load(url, f); item = getRootItem()->findChild<QQuickItem*>(name); } if (item) { QQmlProperty(item, OFFSCREEN_VISIBILITY_PROPERTY).write(true); }} void OffscreenUi::hideDesktopWindows() { if (_desktop) { if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "hideDesktopWindows"); } QMetaObject::invokeMethod(_desktop, "hideDesktopWindows"); }} void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) { QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name); if (!item) { show(url, name, f); return; } // Already loaded, so just flip the bit QQmlProperty shownProperty(item, OFFSCREEN_VISIBILITY_PROPERTY); shownProperty.write(!shownProperty.read().toBool());} bool OffscreenUi::isPointOnDesktopWindow(QVariant point) { if (_desktop) { QVariant result; BLOCKING_INVOKE_METHOD(_desktop, "isPointOnWindow", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, point)); return result.toBool(); } return false;} void OffscreenUi::hide(const QString& name) { auto rootItem = getRootItem(); if (rootItem) { QQuickItem* item = rootItem->findChild<QQuickItem*>(name); if (item) { QQmlProperty(item, OFFSCREEN_VISIBILITY_PROPERTY).write(false); } }} bool OffscreenUi::isVisible(const QString& name) { auto rootItem = getRootItem(); if (rootItem) { QQuickItem* item = rootItem->findChild<QQuickItem*>(name); if (item) { return QQmlProperty(item, OFFSCREEN_VISIBILITY_PROPERTY).read().toBool(); } } return false;} class MessageBoxListener : public ModalDialogListener { Q_OBJECT friend class OffscreenUi; MessageBoxListener(QQuickItem* messageBox) : ModalDialogListener(messageBox) { if (_finished) { return; } connect(_dialog, SIGNAL(selected(int)), this, SLOT(onSelected(int))); } virtual QMessageBox::StandardButton waitForButtonResult() { ModalDialogListener::waitForResult(); return static_cast<QMessageBox::StandardButton>(_result.toInt()); } protected slots: virtual void onDestroyed() override { ModalDialogListener::onDestroyed(); onSelected(QMessageBox::NoButton); } private slots: void onSelected(int button) { _result = button; _finished = true; auto offscreenUi = DependencyManager::get<OffscreenUi>(); emit response(_result); if (!offscreenUi.isNull()) { offscreenUi->removeModalDialog(qobject_cast<QObject*>(this)); } disconnect(_dialog); }}; QQuickItem* OffscreenUi::createMessageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { QVariantMap map; map.insert("title", title); map.insert("text", text); map.insert("icon", icon); map.insert("buttons", buttons.operator int()); map.insert("defaultButton", defaultButton); QVariant result; bool invokeResult = false; auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); if (tablet->getToolbarMode() && _desktop) { invokeResult = QMetaObject::invokeMethod(_desktop, "messageBox", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, QVariant::fromValue(map))); } else if (QQuickItem* tabletRoot = tablet->getTabletRoot()) { invokeResult = QMetaObject::invokeMethod(tabletRoot, "messageBox", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, QVariant::fromValue(map))); emit tabletScriptingInterface->tabletNotification(); } if (!invokeResult) { qWarning() << "Failed to create message box"; return nullptr; } return qvariant_cast<QQuickItem*>(result);} int OffscreenUi::waitForMessageBoxResult(QQuickItem* messageBox) { if (!messageBox) { return QMessageBox::NoButton; } return MessageBoxListener(messageBox).waitForButtonResult();} QMessageBox::StandardButton OffscreenUi::messageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { if (QThread::currentThread() != thread()) { QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton; BLOCKING_INVOKE_METHOD(this, "messageBox", Q_RETURN_ARG(QMessageBox::StandardButton, result), Q_ARG(Icon, icon), Q_ARG(QString, title), Q_ARG(QString, text), Q_ARG(QMessageBox::StandardButtons, buttons), Q_ARG(QMessageBox::StandardButton, defaultButton)); return result; } return static_cast<QMessageBox::StandardButton>(waitForMessageBoxResult(createMessageBox(icon, title, text, buttons, defaultButton)));} ModalDialogListener* OffscreenUi::asyncMessageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "asyncMessageBox", Q_RETURN_ARG(ModalDialogListener*, ret), Q_ARG(Icon, icon), Q_ARG(QString, title), Q_ARG(QString, text), Q_ARG(QMessageBox::StandardButtons, buttons), Q_ARG(QMessageBox::StandardButton, defaultButton)); return ret; } MessageBoxListener* messageBoxListener = new MessageBoxListener(createMessageBox(icon, title, text, buttons, defaultButton)); QObject* modalDialog = qobject_cast<QObject*>(messageBoxListener); _modalDialogListeners.push_back(modalDialog); return messageBoxListener;} QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_CRITICAL, title, text, buttons, defaultButton);}QMessageBox::StandardButton OffscreenUi::information(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_INFORMATION, title, text, buttons, defaultButton);} ModalDialogListener* OffscreenUi::asyncCritical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->asyncMessageBox(OffscreenUi::Icon::ICON_CRITICAL, title, text, buttons, defaultButton);} ModalDialogListener* OffscreenUi::asyncInformation(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->asyncMessageBox(OffscreenUi::Icon::ICON_INFORMATION, title, text, buttons, defaultButton);} QMessageBox::StandardButton OffscreenUi::question(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_QUESTION, title, text, buttons, defaultButton);} ModalDialogListener *OffscreenUi::asyncQuestion(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->asyncMessageBox(OffscreenUi::Icon::ICON_QUESTION, title, text, buttons, defaultButton);} QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_WARNING, title, text, buttons, defaultButton);} ModalDialogListener* OffscreenUi::asyncWarning(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->asyncMessageBox(OffscreenUi::Icon::ICON_WARNING, title, text, buttons, defaultButton);} class InputDialogListener : public ModalDialogListener { Q_OBJECT friend class OffscreenUi; InputDialogListener(QQuickItem* queryBox) : ModalDialogListener(queryBox) { if (_finished) { return; } connect(_dialog, SIGNAL(selected(QVariant)), this, SLOT(onSelected(const QVariant&))); connect(_dialog, SIGNAL(canceled()), this, SLOT(onSelected())); } private slots: void onSelected(const QVariant& result = "") { _result = result; auto offscreenUi = DependencyManager::get<OffscreenUi>(); emit response(_result); offscreenUi->removeModalDialog(qobject_cast<QObject*>(this)); _finished = true; disconnect(_dialog); }}; QString OffscreenUi::getText(const Icon icon, const QString& title, const QString& label, const QString& text, bool* ok) { if (ok) { *ok = false; } QVariant result = DependencyManager::get<OffscreenUi>()->inputDialog(icon, title, label, text).toString(); if (ok && result.isValid()) { *ok = true; } return result.toString();} QString OffscreenUi::getItem(const Icon icon, const QString& title, const QString& label, const QStringList& items, int current, bool editable, bool* ok) { if (ok) { *ok = false; } auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto inputDialog = offscreenUi->createInputDialog(icon, title, label, current); if (!inputDialog) { return QString(); } inputDialog->setProperty("items", items); inputDialog->setProperty("editable", editable); QVariant result = offscreenUi->waitForInputDialogResult(inputDialog); if (!result.isValid()) { return QString(); } if (ok) { *ok = true; } return result.toString();} ModalDialogListener* OffscreenUi::getTextAsync(const Icon icon, const QString& title, const QString& label, const QString& text) { return DependencyManager::get<OffscreenUi>()->inputDialogAsync(icon, title, label, text);} ModalDialogListener* OffscreenUi::getItemAsync(const Icon icon, const QString& title, const QString& label, const QStringList& items, int current, bool editable) { auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto inputDialog = offscreenUi->createInputDialog(icon, title, label, current); if (!inputDialog) { return nullptr; } inputDialog->setProperty("items", items); inputDialog->setProperty("editable", editable); InputDialogListener* inputDialogListener = new InputDialogListener(inputDialog); offscreenUi->getModalDialogListeners().push_back(qobject_cast<QObject*>(inputDialogListener)); return inputDialogListener;} QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const QString& label, const QVariant& current) { if (QThread::currentThread() != thread()) { QVariant result; BLOCKING_INVOKE_METHOD(this, "inputDialog", Q_RETURN_ARG(QVariant, result), Q_ARG(Icon, icon), Q_ARG(QString, title), Q_ARG(QString, label), Q_ARG(QVariant, current)); return result; } return waitForInputDialogResult(createInputDialog(icon, title, label, current));} ModalDialogListener* OffscreenUi::inputDialogAsync(const Icon icon, const QString& title, const QString& label, const QVariant& current) { if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "inputDialogAsync", Q_RETURN_ARG(ModalDialogListener*, ret), Q_ARG(Icon, icon), Q_ARG(QString, title), Q_ARG(QString, label), Q_ARG(QVariant, current)); return ret; } InputDialogListener* inputDialogListener = new InputDialogListener(createInputDialog(icon, title, label, current)); QObject* inputDialog = qobject_cast<QObject*>(inputDialogListener);Lines 1–500 of 1212. Load more
// // OffscreenUi.cpp // interface/src/render-utils // // Created by Bradley Austin Davis on 2015-04-04 // Copyright 2015 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 "OffscreenUi.h" #include <QtCore/QVariant> #include <QtGui/QGuiApplication> #include <QtQuick/QQuickWindow> #include <QtQml/QtQml> #include <shared/QtHelpers.h> #include <gl/GLHelpers.h> #include <AbstractUriHandler.h> #include <AccountManager.h> #include <DependencyManager.h> #include "ui/TabletScriptingInterface.h" #include "FileDialogHelper.h" #include "VrMenu.h" #include "ui/Logging.h" #include "ui/ToolbarScriptingInterface.h" #include <PointerManager.h> #include "MainWindow.h" /*@jsdoc * The <code>OffscreenFlags</code> API enables gamepad joystick navigation of UI. * * <p><em>This API currently has no effect and is not used.</em></p> * * @namespace OffscreenFlags * * @hifi-interface * @hifi-client-entity * @hifi-avatar * * @property {boolean} navigationFocused - <code>true</code> if UI has joystick navigation focus, <code>false</code> if it * doesn't. * @property {boolean} navigationFocusDisabled - <code>true</code> if UI joystick navigation focus is disabled, * <code>false</code> if it isn't. */ // Needs to match the constants in resources/qml/Global.js class OffscreenFlags : public QObject { Q_OBJECT Q_PROPERTY(bool navigationFocused READ isNavigationFocused WRITE setNavigationFocused NOTIFY navigationFocusedChanged) // Allow scripts that are doing their own navigation support to disable navigation focus (i.e. handControllerPointer.js) Q_PROPERTY(bool navigationFocusDisabled READ isNavigationFocusDisabled WRITE setNavigationFocusDisabled NOTIFY navigationFocusDisabledChanged) public: OffscreenFlags(QObject* parent = nullptr) : QObject(parent) {} bool isNavigationFocused() const { return _navigationFocused; } void setNavigationFocused(bool focused) { if (_navigationFocused != focused) { _navigationFocused = focused; emit navigationFocusedChanged(); } } bool isNavigationFocusDisabled() const { return _navigationFocusDisabled; } void setNavigationFocusDisabled(bool disabled) { if (_navigationFocusDisabled != disabled) { _navigationFocusDisabled = disabled; emit navigationFocusDisabledChanged(); } } signals: /*@jsdoc * Triggered when the value of the <code>navigationFocused</code> property changes. * @function OffscreenFlags.navigationFocusedChanged * @returns {Signal} */ void navigationFocusedChanged(); /*@jsdoc * Triggered when the value of the <code>navigationFocusDisabled</code> property changes. * @function OffscreenFlags.navigationFocusDisabledChanged * @returns {Signal} */ void navigationFocusDisabledChanged(); private: bool _navigationFocused { false }; bool _navigationFocusDisabled{ false }; }; static OffscreenFlags* offscreenFlags { nullptr }; // This hack allows the QML UI to work with keys that are also bound as // shortcuts at the application level. However, it seems as though the // bound actions are still getting triggered. At least for backspace. // Not sure why. // // However, the problem may go away once we switch to the new menu system, // so I think it's OK for the time being. bool OffscreenUi::shouldSwallowShortcut(QEvent* event) { Q_ASSERT(event->type() == QEvent::ShortcutOverride); auto window = getWindow(); if (window) { QObject* focusObject = getWindow()->focusObject(); if (focusObject != getWindow() && focusObject != getRootItem()) { event->accept(); return true; } } return false; } static QTouchDevice _touchDevice; OffscreenUi::OffscreenUi() { static std::once_flag once; std::call_once(once, [&] { _touchDevice.setCapabilities(QTouchDevice::Position); _touchDevice.setType(QTouchDevice::TouchScreen); _touchDevice.setName("OffscreenUiTouchDevice"); _touchDevice.setMaximumTouchPoints(4); }); auto pointerManager = DependencyManager::get<PointerManager>(); connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &OffscreenUi::hoverBeginEvent); connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &OffscreenUi::handlePointerEvent); connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &OffscreenUi::hoverEndEvent); connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &OffscreenUi::handlePointerEvent); connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &OffscreenUi::handlePointerEvent); connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &OffscreenUi::handlePointerEvent); connect(pointerManager.data(), &PointerManager::scrollHUD, this, &OffscreenUi::handlePointerEvent); } void OffscreenUi::hoverBeginEvent(const PointerEvent& event) { OffscreenQmlSurface::hoverBeginEvent(event, _touchDevice); } void OffscreenUi::hoverEndEvent(const PointerEvent& event) { OffscreenQmlSurface::hoverEndEvent(event, _touchDevice); } void OffscreenUi::handlePointerEvent(const PointerEvent& event) { OffscreenQmlSurface::handlePointerEvent(event, _touchDevice); } QObject* OffscreenUi::getFlags() { return offscreenFlags; } void OffscreenUi::removeModalDialog(QObject* modal) { if (modal) { _modalDialogListeners.removeOne(modal); modal->deleteLater(); } } void OffscreenUi::onRootContextCreated(QQmlContext* qmlContext) { OffscreenQmlSurface::onRootContextCreated(qmlContext); qmlContext->setContextProperty("OffscreenUi", this); qmlContext->setContextProperty("offscreenFlags", offscreenFlags = new OffscreenFlags()); qmlContext->setContextProperty("fileDialogHelper", new FileDialogHelper()); #ifdef DEBUG qmlContext->setContextProperty("DebugQML", QVariant(true)); #else qmlContext->setContextProperty("DebugQML", QVariant(false)); #endif } void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) { emit showDesktop(); QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name); // First load? if (!item) { load(url, f); item = getRootItem()->findChild<QQuickItem*>(name); } if (item) { QQmlProperty(item, OFFSCREEN_VISIBILITY_PROPERTY).write(true); } } void OffscreenUi::hideDesktopWindows() { if (_desktop) { if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(this, "hideDesktopWindows"); } QMetaObject::invokeMethod(_desktop, "hideDesktopWindows"); } } void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) { QQuickItem* item = getRootItem()->findChild<QQuickItem*>(name); if (!item) { show(url, name, f); return; } // Already loaded, so just flip the bit QQmlProperty shownProperty(item, OFFSCREEN_VISIBILITY_PROPERTY); shownProperty.write(!shownProperty.read().toBool()); } bool OffscreenUi::isPointOnDesktopWindow(QVariant point) { if (_desktop) { QVariant result; BLOCKING_INVOKE_METHOD(_desktop, "isPointOnWindow", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, point)); return result.toBool(); } return false; } void OffscreenUi::hide(const QString& name) { auto rootItem = getRootItem(); if (rootItem) { QQuickItem* item = rootItem->findChild<QQuickItem*>(name); if (item) { QQmlProperty(item, OFFSCREEN_VISIBILITY_PROPERTY).write(false); } } } bool OffscreenUi::isVisible(const QString& name) { auto rootItem = getRootItem(); if (rootItem) { QQuickItem* item = rootItem->findChild<QQuickItem*>(name); if (item) { return QQmlProperty(item, OFFSCREEN_VISIBILITY_PROPERTY).read().toBool(); } } return false; } class MessageBoxListener : public ModalDialogListener { Q_OBJECT friend class OffscreenUi; MessageBoxListener(QQuickItem* messageBox) : ModalDialogListener(messageBox) { if (_finished) { return; } connect(_dialog, SIGNAL(selected(int)), this, SLOT(onSelected(int))); } virtual QMessageBox::StandardButton waitForButtonResult() { ModalDialogListener::waitForResult(); return static_cast<QMessageBox::StandardButton>(_result.toInt()); } protected slots: virtual void onDestroyed() override { ModalDialogListener::onDestroyed(); onSelected(QMessageBox::NoButton); } private slots: void onSelected(int button) { _result = button; _finished = true; auto offscreenUi = DependencyManager::get<OffscreenUi>(); emit response(_result); if (!offscreenUi.isNull()) { offscreenUi->removeModalDialog(qobject_cast<QObject*>(this)); } disconnect(_dialog); } }; QQuickItem* OffscreenUi::createMessageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { QVariantMap map; map.insert("title", title); map.insert("text", text); map.insert("icon", icon); map.insert("buttons", buttons.operator int()); map.insert("defaultButton", defaultButton); QVariant result; bool invokeResult = false; auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); if (tablet->getToolbarMode() && _desktop) { invokeResult = QMetaObject::invokeMethod(_desktop, "messageBox", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, QVariant::fromValue(map))); } else if (QQuickItem* tabletRoot = tablet->getTabletRoot()) { invokeResult = QMetaObject::invokeMethod(tabletRoot, "messageBox", Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, QVariant::fromValue(map))); emit tabletScriptingInterface->tabletNotification(); } if (!invokeResult) { qWarning() << "Failed to create message box"; return nullptr; } return qvariant_cast<QQuickItem*>(result); } int OffscreenUi::waitForMessageBoxResult(QQuickItem* messageBox) { if (!messageBox) { return QMessageBox::NoButton; } return MessageBoxListener(messageBox).waitForButtonResult(); } QMessageBox::StandardButton OffscreenUi::messageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { if (QThread::currentThread() != thread()) { QMessageBox::StandardButton result = QMessageBox::StandardButton::NoButton; BLOCKING_INVOKE_METHOD(this, "messageBox", Q_RETURN_ARG(QMessageBox::StandardButton, result), Q_ARG(Icon, icon), Q_ARG(QString, title), Q_ARG(QString, text), Q_ARG(QMessageBox::StandardButtons, buttons), Q_ARG(QMessageBox::StandardButton, defaultButton)); return result; } return static_cast<QMessageBox::StandardButton>(waitForMessageBoxResult(createMessageBox(icon, title, text, buttons, defaultButton))); } ModalDialogListener* OffscreenUi::asyncMessageBox(Icon icon, const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "asyncMessageBox", Q_RETURN_ARG(ModalDialogListener*, ret), Q_ARG(Icon, icon), Q_ARG(QString, title), Q_ARG(QString, text), Q_ARG(QMessageBox::StandardButtons, buttons), Q_ARG(QMessageBox::StandardButton, defaultButton)); return ret; } MessageBoxListener* messageBoxListener = new MessageBoxListener(createMessageBox(icon, title, text, buttons, defaultButton)); QObject* modalDialog = qobject_cast<QObject*>(messageBoxListener); _modalDialogListeners.push_back(modalDialog); return messageBoxListener; } QMessageBox::StandardButton OffscreenUi::critical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_CRITICAL, title, text, buttons, defaultButton); } QMessageBox::StandardButton OffscreenUi::information(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_INFORMATION, title, text, buttons, defaultButton); } ModalDialogListener* OffscreenUi::asyncCritical(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->asyncMessageBox(OffscreenUi::Icon::ICON_CRITICAL, title, text, buttons, defaultButton); } ModalDialogListener* OffscreenUi::asyncInformation(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->asyncMessageBox(OffscreenUi::Icon::ICON_INFORMATION, title, text, buttons, defaultButton); } QMessageBox::StandardButton OffscreenUi::question(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_QUESTION, title, text, buttons, defaultButton); } ModalDialogListener *OffscreenUi::asyncQuestion(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->asyncMessageBox(OffscreenUi::Icon::ICON_QUESTION, title, text, buttons, defaultButton); } QMessageBox::StandardButton OffscreenUi::warning(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->messageBox(OffscreenUi::Icon::ICON_WARNING, title, text, buttons, defaultButton); } ModalDialogListener* OffscreenUi::asyncWarning(const QString& title, const QString& text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) { return DependencyManager::get<OffscreenUi>()->asyncMessageBox(OffscreenUi::Icon::ICON_WARNING, title, text, buttons, defaultButton); } class InputDialogListener : public ModalDialogListener { Q_OBJECT friend class OffscreenUi; InputDialogListener(QQuickItem* queryBox) : ModalDialogListener(queryBox) { if (_finished) { return; } connect(_dialog, SIGNAL(selected(QVariant)), this, SLOT(onSelected(const QVariant&))); connect(_dialog, SIGNAL(canceled()), this, SLOT(onSelected())); } private slots: void onSelected(const QVariant& result = "") { _result = result; auto offscreenUi = DependencyManager::get<OffscreenUi>(); emit response(_result); offscreenUi->removeModalDialog(qobject_cast<QObject*>(this)); _finished = true; disconnect(_dialog); } }; QString OffscreenUi::getText(const Icon icon, const QString& title, const QString& label, const QString& text, bool* ok) { if (ok) { *ok = false; } QVariant result = DependencyManager::get<OffscreenUi>()->inputDialog(icon, title, label, text).toString(); if (ok && result.isValid()) { *ok = true; } return result.toString(); } QString OffscreenUi::getItem(const Icon icon, const QString& title, const QString& label, const QStringList& items, int current, bool editable, bool* ok) { if (ok) { *ok = false; } auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto inputDialog = offscreenUi->createInputDialog(icon, title, label, current); if (!inputDialog) { return QString(); } inputDialog->setProperty("items", items); inputDialog->setProperty("editable", editable); QVariant result = offscreenUi->waitForInputDialogResult(inputDialog); if (!result.isValid()) { return QString(); } if (ok) { *ok = true; } return result.toString(); } ModalDialogListener* OffscreenUi::getTextAsync(const Icon icon, const QString& title, const QString& label, const QString& text) { return DependencyManager::get<OffscreenUi>()->inputDialogAsync(icon, title, label, text); } ModalDialogListener* OffscreenUi::getItemAsync(const Icon icon, const QString& title, const QString& label, const QStringList& items, int current, bool editable) { auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto inputDialog = offscreenUi->createInputDialog(icon, title, label, current); if (!inputDialog) { return nullptr; } inputDialog->setProperty("items", items); inputDialog->setProperty("editable", editable); InputDialogListener* inputDialogListener = new InputDialogListener(inputDialog); offscreenUi->getModalDialogListeners().push_back(qobject_cast<QObject*>(inputDialogListener)); return inputDialogListener; } QVariant OffscreenUi::inputDialog(const Icon icon, const QString& title, const QString& label, const QVariant& current) { if (QThread::currentThread() != thread()) { QVariant result; BLOCKING_INVOKE_METHOD(this, "inputDialog", Q_RETURN_ARG(QVariant, result), Q_ARG(Icon, icon), Q_ARG(QString, title), Q_ARG(QString, label), Q_ARG(QVariant, current)); return result; } return waitForInputDialogResult(createInputDialog(icon, title, label, current)); } ModalDialogListener* OffscreenUi::inputDialogAsync(const Icon icon, const QString& title, const QString& label, const QVariant& current) { if (QThread::currentThread() != thread()) { ModalDialogListener* ret; BLOCKING_INVOKE_METHOD(this, "inputDialogAsync", Q_RETURN_ARG(ModalDialogListener*, ret), Q_ARG(Icon, icon), Q_ARG(QString, title), Q_ARG(QString, label), Q_ARG(QVariant, current)); return ret; } InputDialogListener* inputDialogListener = new InputDialogListener(createInputDialog(icon, title, label, current)); QObject* inputDialog = qobject_cast<QObject*>(inputDialogListener);