mirror of
https://github.com/overte-org/overte.git
synced 2025-08-07 03:50:16 +02:00
Additional thread safety
This commit is contained in:
parent
b52dd7b822
commit
8372d73fec
23 changed files with 413 additions and 249 deletions
|
@ -63,10 +63,7 @@ void RenderingClient::sendAvatarPacket() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingClient::cleanupBeforeQuit() {
|
void RenderingClient::cleanupBeforeQuit() {
|
||||||
|
DependencyManager::get<AudioClient>()->cleanupBeforeQuit();
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
|
|
||||||
"stop", Qt::BlockingQueuedConnection);
|
|
||||||
|
|
||||||
// destroy the AudioClient so it and its thread will safely go down
|
// destroy the AudioClient so it and its thread will safely go down
|
||||||
DependencyManager::destroy<AudioClient>();
|
DependencyManager::destroy<AudioClient>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1844,7 +1844,7 @@ void Application::cleanupBeforeQuit() {
|
||||||
|
|
||||||
// FIXME: something else is holding a reference to AudioClient,
|
// FIXME: something else is holding a reference to AudioClient,
|
||||||
// so it must be explicitly synchronously stopped here
|
// so it must be explicitly synchronously stopped here
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "cleanupBeforeQuit", Qt::BlockingQueuedConnection);
|
DependencyManager::get<AudioClient>()->cleanupBeforeQuit();
|
||||||
|
|
||||||
// destroy Audio so it and its threads have a chance to go down safely
|
// destroy Audio so it and its threads have a chance to go down safely
|
||||||
// this must happen after QML, as there are unexplained audio crashes originating in qtwebengine
|
// this must happen after QML, as there are unexplained audio crashes originating in qtwebengine
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <QtScript/QScriptContext>
|
#include <QtScript/QScriptContext>
|
||||||
|
|
||||||
|
#include <shared/QtHelpers.h>
|
||||||
#include <avatar/AvatarManager.h>
|
#include <avatar/AvatarManager.h>
|
||||||
#include <display-plugins/DisplayPlugin.h>
|
#include <display-plugins/DisplayPlugin.h>
|
||||||
#include <display-plugins/CompositorHelper.h>
|
#include <display-plugins/CompositorHelper.h>
|
||||||
|
@ -152,22 +153,31 @@ QString HMDScriptingInterface::preferredAudioOutput() const {
|
||||||
return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice();
|
return qApp->getActiveDisplayPlugin()->getPreferredAudioOutDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HMDScriptingInterface::setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const {
|
bool HMDScriptingInterface::setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
bool result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "setHandLasers", Q_RETURN_ARG(bool, result),
|
||||||
|
Q_ARG(int, hands), Q_ARG(bool, enabled), Q_ARG(glm::vec4, color), Q_ARG(glm::vec3, direction));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->executeOnUiThread([offscreenUi, enabled] {
|
offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled);
|
||||||
offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled);
|
|
||||||
});
|
|
||||||
return qApp->getActiveDisplayPlugin()->setHandLaser(hands,
|
return qApp->getActiveDisplayPlugin()->setHandLaser(hands,
|
||||||
enabled ? DisplayPlugin::HandLaserMode::Overlay : DisplayPlugin::HandLaserMode::None,
|
enabled ? DisplayPlugin::HandLaserMode::Overlay : DisplayPlugin::HandLaserMode::None,
|
||||||
color, direction);
|
color, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) const {
|
bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) {
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
if (QThread::currentThread() != thread()) {
|
||||||
offscreenUi->executeOnUiThread([offscreenUi, enabled] {
|
bool result;
|
||||||
offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled);
|
hifi::qt::blockingInvokeMethod(this, "setExtraLaser", Q_RETURN_ARG(bool, result),
|
||||||
});
|
Q_ARG(glm::vec3, worldStart), Q_ARG(bool, enabled), Q_ARG(glm::vec4, color), Q_ARG(glm::vec3, direction));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
|
offscreenUi->getDesktop()->setProperty("hmdHandMouseActive", enabled);
|
||||||
|
|
||||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
auto sensorToWorld = myAvatar->getSensorToWorldMatrix();
|
auto sensorToWorld = myAvatar->getSensorToWorldMatrix();
|
||||||
|
@ -179,11 +189,11 @@ bool HMDScriptingInterface::setExtraLaser(const glm::vec3& worldStart, bool enab
|
||||||
color, sensorStart, sensorDirection);
|
color, sensorStart, sensorDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HMDScriptingInterface::disableExtraLaser() const {
|
void HMDScriptingInterface::disableExtraLaser() {
|
||||||
setExtraLaser(vec3(0), false, vec4(0), vec3(0));
|
setExtraLaser(vec3(0), false, vec4(0), vec3(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HMDScriptingInterface::disableHandLasers(int hands) const {
|
void HMDScriptingInterface::disableHandLasers(int hands) {
|
||||||
setHandLasers(hands, false, vec4(0), vec3(0));
|
setHandLasers(hands, false, vec4(0), vec3(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,11 +51,11 @@ public:
|
||||||
Q_INVOKABLE void requestHideHandControllers();
|
Q_INVOKABLE void requestHideHandControllers();
|
||||||
Q_INVOKABLE bool shouldShowHandControllers() const;
|
Q_INVOKABLE bool shouldShowHandControllers() const;
|
||||||
|
|
||||||
Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction) const;
|
Q_INVOKABLE bool setHandLasers(int hands, bool enabled, const glm::vec4& color, const glm::vec3& direction);
|
||||||
Q_INVOKABLE void disableHandLasers(int hands) const;
|
Q_INVOKABLE void disableHandLasers(int hands);
|
||||||
|
|
||||||
Q_INVOKABLE bool setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction) const;
|
Q_INVOKABLE bool setExtraLaser(const glm::vec3& worldStart, bool enabled, const glm::vec4& color, const glm::vec3& direction);
|
||||||
Q_INVOKABLE void disableExtraLaser() const;
|
Q_INVOKABLE void disableExtraLaser();
|
||||||
|
|
||||||
|
|
||||||
/// Suppress the activation of any on-screen keyboard so that a script operation will
|
/// Suppress the activation of any on-screen keyboard so that a script operation will
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QtCore/QLoggingCategory>
|
#include <QtCore/QLoggingCategory>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
|
#include <shared/QtHelpers.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <Trace.h>
|
#include <Trace.h>
|
||||||
#include <StatTracker.h>
|
#include <StatTracker.h>
|
||||||
|
@ -57,20 +58,25 @@ void TestScriptingInterface::waitIdle() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestScriptingInterface::loadTestScene(QString scene) {
|
bool TestScriptingInterface::loadTestScene(QString scene) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
bool result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "loadTestScene", Q_RETURN_ARG(bool, result), Q_ARG(QString, scene));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static const QString TEST_ROOT = "https://raw.githubusercontent.com/highfidelity/hifi_tests/master/";
|
static const QString TEST_ROOT = "https://raw.githubusercontent.com/highfidelity/hifi_tests/master/";
|
||||||
static const QString TEST_BINARY_ROOT = "https://hifi-public.s3.amazonaws.com/test_scene_data/";
|
static const QString TEST_BINARY_ROOT = "https://hifi-public.s3.amazonaws.com/test_scene_data/";
|
||||||
static const QString TEST_SCRIPTS_ROOT = TEST_ROOT + "scripts/";
|
static const QString TEST_SCRIPTS_ROOT = TEST_ROOT + "scripts/";
|
||||||
static const QString TEST_SCENES_ROOT = TEST_ROOT + "scenes/";
|
static const QString TEST_SCENES_ROOT = TEST_ROOT + "scenes/";
|
||||||
return DependencyManager::get<OffscreenUi>()->returnFromUiThread([scene]()->QVariant {
|
|
||||||
DependencyManager::get<ResourceManager>()->setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/");
|
DependencyManager::get<ResourceManager>()->setUrlPrefixOverride("atp:/", TEST_BINARY_ROOT + scene + ".atp/");
|
||||||
auto tree = qApp->getEntities()->getTree();
|
auto tree = qApp->getEntities()->getTree();
|
||||||
auto treeIsClient = tree->getIsClient();
|
auto treeIsClient = tree->getIsClient();
|
||||||
// Force the tree to accept the load regardless of permissions
|
// Force the tree to accept the load regardless of permissions
|
||||||
tree->setIsClient(false);
|
tree->setIsClient(false);
|
||||||
auto result = tree->readFromURL(TEST_SCENES_ROOT + scene + ".json");
|
auto result = tree->readFromURL(TEST_SCENES_ROOT + scene + ".json");
|
||||||
tree->setIsClient(treeIsClient);
|
tree->setIsClient(treeIsClient);
|
||||||
return result;
|
return result;
|
||||||
}).toBool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestScriptingInterface::startTracing(QString logrules) {
|
bool TestScriptingInterface::startTracing(QString logrules) {
|
||||||
|
|
|
@ -45,11 +45,13 @@ Image3DOverlay::~Image3DOverlay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image3DOverlay::update(float deltatime) {
|
void Image3DOverlay::update(float deltatime) {
|
||||||
|
#if OVERLAY_PANELS
|
||||||
if (usecTimestampNow() > _transformExpiry) {
|
if (usecTimestampNow() > _transformExpiry) {
|
||||||
Transform transform = getTransform();
|
Transform transform = getTransform();
|
||||||
applyTransformTo(transform);
|
applyTransformTo(transform);
|
||||||
setTransform(transform);
|
setTransform(transform);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image3DOverlay::render(RenderArgs* args) {
|
void Image3DOverlay::render(RenderArgs* args) {
|
||||||
|
|
|
@ -84,9 +84,9 @@ public:
|
||||||
void setColorPulse(float value) { _colorPulse = value; }
|
void setColorPulse(float value) { _colorPulse = value; }
|
||||||
void setAlphaPulse(float value) { _alphaPulse = value; }
|
void setAlphaPulse(float value) { _alphaPulse = value; }
|
||||||
|
|
||||||
virtual void setProperties(const QVariantMap& properties);
|
Q_INVOKABLE virtual void setProperties(const QVariantMap& properties);
|
||||||
virtual Overlay* createClone() const = 0;
|
Q_INVOKABLE virtual Overlay* createClone() const = 0;
|
||||||
virtual QVariant getProperty(const QString& property);
|
Q_INVOKABLE virtual QVariant getProperty(const QString& property);
|
||||||
|
|
||||||
render::ItemID getRenderItemID() const { return _renderItemID; }
|
render::ItemID getRenderItemID() const { return _renderItemID; }
|
||||||
void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; }
|
void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; }
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "OverlayPanel.h"
|
#include "OverlayPanel.h"
|
||||||
|
|
||||||
|
#if OVERLAY_PANELS
|
||||||
|
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
@ -185,3 +187,4 @@ void OverlayPanel::applyTransformTo(Transform& transform, bool force) {
|
||||||
pointTransformAtCamera(transform, getOffsetRotation());
|
pointTransformAtCamera(transform, getOffsetRotation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
|
@ -22,6 +22,7 @@
|
||||||
#include "Billboardable.h"
|
#include "Billboardable.h"
|
||||||
#include "Overlay.h"
|
#include "Overlay.h"
|
||||||
|
|
||||||
|
#if OVERLAY_PANELS
|
||||||
class PropertyBinding {
|
class PropertyBinding {
|
||||||
public:
|
public:
|
||||||
PropertyBinding() {}
|
PropertyBinding() {}
|
||||||
|
@ -80,4 +81,6 @@ private:
|
||||||
QScriptEngine* _scriptEngine;
|
QScriptEngine* _scriptEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // hifi_OverlayPanel_h
|
#endif // hifi_OverlayPanel_h
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <QtScript/QScriptValueIterator>
|
#include <QtScript/QScriptValueIterator>
|
||||||
|
|
||||||
|
#include <shared/QtHelpers.h>
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
#include <render/Scene.h>
|
#include <render/Scene.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
|
@ -40,8 +41,6 @@ Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays")
|
||||||
|
|
||||||
void Overlays::cleanupAllOverlays() {
|
void Overlays::cleanupAllOverlays() {
|
||||||
{
|
{
|
||||||
QWriteLocker lock(&_lock);
|
|
||||||
QWriteLocker deleteLock(&_deleteLock);
|
|
||||||
foreach(Overlay::Pointer overlay, _overlaysHUD) {
|
foreach(Overlay::Pointer overlay, _overlaysHUD) {
|
||||||
_overlaysToDelete.push_back(overlay);
|
_overlaysToDelete.push_back(overlay);
|
||||||
}
|
}
|
||||||
|
@ -50,19 +49,22 @@ void Overlays::cleanupAllOverlays() {
|
||||||
}
|
}
|
||||||
_overlaysHUD.clear();
|
_overlaysHUD.clear();
|
||||||
_overlaysWorld.clear();
|
_overlaysWorld.clear();
|
||||||
|
#if OVERLAY_PANELS
|
||||||
_panels.clear();
|
_panels.clear();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
cleanupOverlaysToDelete();
|
cleanupOverlaysToDelete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::init() {
|
void Overlays::init() {
|
||||||
|
#if OVERLAY_PANELS
|
||||||
_scriptEngine = new QScriptEngine();
|
_scriptEngine = new QScriptEngine();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::update(float deltatime) {
|
void Overlays::update(float deltatime) {
|
||||||
|
|
||||||
{
|
{
|
||||||
QWriteLocker lock(&_lock);
|
|
||||||
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
|
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
|
||||||
thisOverlay->update(deltatime);
|
thisOverlay->update(deltatime);
|
||||||
}
|
}
|
||||||
|
@ -80,8 +82,6 @@ void Overlays::cleanupOverlaysToDelete() {
|
||||||
render::Transaction transaction;
|
render::Transaction transaction;
|
||||||
|
|
||||||
{
|
{
|
||||||
QWriteLocker lock(&_deleteLock);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
Overlay::Pointer overlay = _overlaysToDelete.takeLast();
|
Overlay::Pointer overlay = _overlaysToDelete.takeLast();
|
||||||
|
|
||||||
|
@ -100,7 +100,6 @@ void Overlays::cleanupOverlaysToDelete() {
|
||||||
|
|
||||||
void Overlays::renderHUD(RenderArgs* renderArgs) {
|
void Overlays::renderHUD(RenderArgs* renderArgs) {
|
||||||
PROFILE_RANGE(render_overlays, __FUNCTION__);
|
PROFILE_RANGE(render_overlays, __FUNCTION__);
|
||||||
QReadLocker lock(&_lock);
|
|
||||||
gpu::Batch& batch = *renderArgs->_batch;
|
gpu::Batch& batch = *renderArgs->_batch;
|
||||||
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
|
@ -126,12 +125,10 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::disable() {
|
void Overlays::disable() {
|
||||||
QWriteLocker lock(&_lock);
|
|
||||||
_enabled = false;
|
_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::enable() {
|
void Overlays::enable() {
|
||||||
QWriteLocker lock(&_lock);
|
|
||||||
_enabled = true;
|
_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +143,12 @@ Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) {
|
OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
OverlayID result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "addOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(QString, type), Q_ARG(QVariant, properties));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay::Pointer thisOverlay = nullptr;
|
Overlay::Pointer thisOverlay = nullptr;
|
||||||
|
|
||||||
if (type == ImageOverlay::TYPE) {
|
if (type == ImageOverlay::TYPE) {
|
||||||
|
@ -185,8 +188,7 @@ OverlayID Overlays::addOverlay(const QString& type, const QVariant& properties)
|
||||||
return UNKNOWN_OVERLAY_ID;
|
return UNKNOWN_OVERLAY_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayID Overlays::addOverlay(Overlay::Pointer overlay) {
|
OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
|
||||||
QWriteLocker lock(&_lock);
|
|
||||||
OverlayID thisID = OverlayID(QUuid::createUuid());
|
OverlayID thisID = OverlayID(QUuid::createUuid());
|
||||||
overlay->setOverlayID(thisID);
|
overlay->setOverlayID(thisID);
|
||||||
overlay->setStackOrder(_stackOrder++);
|
overlay->setStackOrder(_stackOrder++);
|
||||||
|
@ -205,14 +207,22 @@ OverlayID Overlays::addOverlay(Overlay::Pointer overlay) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayID Overlays::cloneOverlay(OverlayID id) {
|
OverlayID Overlays::cloneOverlay(OverlayID id) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
OverlayID result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "cloneOverlay", Q_RETURN_ARG(OverlayID, result), Q_ARG(OverlayID, id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
|
|
||||||
if (thisOverlay) {
|
if (thisOverlay) {
|
||||||
OverlayID cloneId = addOverlay(Overlay::Pointer(thisOverlay->createClone()));
|
OverlayID cloneId = addOverlay(Overlay::Pointer(thisOverlay->createClone()));
|
||||||
|
#if OVERLAY_PANELS
|
||||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(thisOverlay);
|
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(thisOverlay);
|
||||||
if (attachable && attachable->getParentPanel()) {
|
if (attachable && attachable->getParentPanel()) {
|
||||||
attachable->getParentPanel()->addChild(cloneId);
|
attachable->getParentPanel()->addChild(cloneId);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return cloneId;
|
return cloneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,21 +230,29 @@ OverlayID Overlays::cloneOverlay(OverlayID id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
|
bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
|
||||||
QWriteLocker lock(&_lock);
|
if (QThread::currentThread() != thread()) {
|
||||||
|
bool result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "editOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id), Q_ARG(QVariant, properties));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
if (thisOverlay) {
|
if (thisOverlay) {
|
||||||
thisOverlay->setProperties(properties.toMap());
|
thisOverlay->setProperties(properties.toMap());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Overlays::editOverlays(const QVariant& propertiesById) {
|
bool Overlays::editOverlays(const QVariant& propertiesById) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
bool result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "editOverlays", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, propertiesById));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap map = propertiesById.toMap();
|
QVariantMap map = propertiesById.toMap();
|
||||||
bool success = true;
|
bool success = true;
|
||||||
QWriteLocker lock(&_lock);
|
|
||||||
for (const auto& key : map.keys()) {
|
for (const auto& key : map.keys()) {
|
||||||
OverlayID id = OverlayID(key);
|
OverlayID id = OverlayID(key);
|
||||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
|
@ -249,10 +267,14 @@ bool Overlays::editOverlays(const QVariant& propertiesById) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::deleteOverlay(OverlayID id) {
|
void Overlays::deleteOverlay(OverlayID id) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "deleteOverlay", Q_ARG(OverlayID, id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay::Pointer overlayToDelete;
|
Overlay::Pointer overlayToDelete;
|
||||||
|
|
||||||
{
|
{
|
||||||
QWriteLocker lock(&_lock);
|
|
||||||
if (_overlaysHUD.contains(id)) {
|
if (_overlaysHUD.contains(id)) {
|
||||||
overlayToDelete = _overlaysHUD.take(id);
|
overlayToDelete = _overlaysHUD.take(id);
|
||||||
} else if (_overlaysWorld.contains(id)) {
|
} else if (_overlaysWorld.contains(id)) {
|
||||||
|
@ -262,19 +284,25 @@ void Overlays::deleteOverlay(OverlayID id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OVERLAY_PANELS
|
||||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlayToDelete);
|
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlayToDelete);
|
||||||
if (attachable && attachable->getParentPanel()) {
|
if (attachable && attachable->getParentPanel()) {
|
||||||
attachable->getParentPanel()->removeChild(id);
|
attachable->getParentPanel()->removeChild(id);
|
||||||
attachable->setParentPanel(nullptr);
|
attachable->setParentPanel(nullptr);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QWriteLocker lock(&_deleteLock);
|
|
||||||
_overlaysToDelete.push_back(overlayToDelete);
|
_overlaysToDelete.push_back(overlayToDelete);
|
||||||
|
|
||||||
emit overlayDeleted(id);
|
emit overlayDeleted(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Overlays::getOverlayType(OverlayID overlayId) const {
|
QString Overlays::getOverlayType(OverlayID overlayId) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QString result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "getOverlayType", Q_RETURN_ARG(QString, result), Q_ARG(OverlayID, overlayId));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay::Pointer overlay = getOverlay(overlayId);
|
Overlay::Pointer overlay = getOverlay(overlayId);
|
||||||
if (overlay) {
|
if (overlay) {
|
||||||
return overlay->getType();
|
return overlay->getType();
|
||||||
|
@ -283,6 +311,12 @@ QString Overlays::getOverlayType(OverlayID overlayId) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
QObject* Overlays::getOverlayObject(OverlayID id) {
|
QObject* Overlays::getOverlayObject(OverlayID id) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QObject* result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "getOverlayObject", Q_RETURN_ARG(QObject*, result), Q_ARG(OverlayID, id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
if (thisOverlay) {
|
if (thisOverlay) {
|
||||||
return qobject_cast<QObject*>(&(*thisOverlay));
|
return qobject_cast<QObject*>(&(*thisOverlay));
|
||||||
|
@ -290,6 +324,7 @@ QObject* Overlays::getOverlayObject(OverlayID id) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OVERLAY_PANELS
|
||||||
OverlayID Overlays::getParentPanel(OverlayID childId) const {
|
OverlayID Overlays::getParentPanel(OverlayID childId) const {
|
||||||
Overlay::Pointer overlay = getOverlay(childId);
|
Overlay::Pointer overlay = getOverlay(childId);
|
||||||
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlay);
|
auto attachable = std::dynamic_pointer_cast<PanelAttachable>(overlay);
|
||||||
|
@ -330,10 +365,16 @@ void Overlays::setParentPanel(OverlayID childId, OverlayID panelId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
OverlayID result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "getOverlayAtPoint", Q_RETURN_ARG(OverlayID, result), Q_ARG(glm::vec2, point));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec2 pointCopy = point;
|
glm::vec2 pointCopy = point;
|
||||||
QReadLocker lock(&_lock);
|
|
||||||
if (!_enabled) {
|
if (!_enabled) {
|
||||||
return UNKNOWN_OVERLAY_ID;
|
return UNKNOWN_OVERLAY_ID;
|
||||||
}
|
}
|
||||||
|
@ -365,9 +406,14 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) {
|
OverlayPropertyResult Overlays::getProperty(OverlayID id, const QString& property) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
OverlayPropertyResult result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "getProperty", Q_RETURN_ARG(OverlayPropertyResult, result), Q_ARG(OverlayID, id), Q_ARG(QString, property));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
OverlayPropertyResult result;
|
OverlayPropertyResult result;
|
||||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
QReadLocker lock(&_lock);
|
|
||||||
if (thisOverlay && thisOverlay->supportsGetProperty()) {
|
if (thisOverlay && thisOverlay->supportsGetProperty()) {
|
||||||
result.value = thisOverlay->getProperty(property);
|
result.value = thisOverlay->getProperty(property);
|
||||||
}
|
}
|
||||||
|
@ -405,7 +451,18 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
|
||||||
const QVector<OverlayID>& overlaysToInclude,
|
const QVector<OverlayID>& overlaysToInclude,
|
||||||
const QVector<OverlayID>& overlaysToDiscard,
|
const QVector<OverlayID>& overlaysToDiscard,
|
||||||
bool visibleOnly, bool collidableOnly) {
|
bool visibleOnly, bool collidableOnly) {
|
||||||
QReadLocker lock(&_lock);
|
if (QThread::currentThread() != thread()) {
|
||||||
|
RayToOverlayIntersectionResult result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "findRayIntersectionInternal", Q_RETURN_ARG(RayToOverlayIntersectionResult, result),
|
||||||
|
Q_ARG(PickRay, ray),
|
||||||
|
Q_ARG(bool, precisionPicking),
|
||||||
|
Q_ARG(QVector<OverlayID>, overlaysToInclude),
|
||||||
|
Q_ARG(QVector<OverlayID>, overlaysToDiscard),
|
||||||
|
Q_ARG(bool, visibleOnly),
|
||||||
|
Q_ARG(bool, collidableOnly));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
float bestDistance = std::numeric_limits<float>::max();
|
float bestDistance = std::numeric_limits<float>::max();
|
||||||
bool bestIsFront = false;
|
bool bestIsFront = false;
|
||||||
|
|
||||||
|
@ -448,16 +505,6 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RayToOverlayIntersectionResult::RayToOverlayIntersectionResult() :
|
|
||||||
intersects(false),
|
|
||||||
overlayID(UNKNOWN_OVERLAY_ID),
|
|
||||||
distance(0),
|
|
||||||
face(),
|
|
||||||
intersection(),
|
|
||||||
extraInfo()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) {
|
QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) {
|
||||||
auto obj = engine->newObject();
|
auto obj = engine->newObject();
|
||||||
obj.setProperty("intersects", value.intersects);
|
obj.setProperty("intersects", value.intersects);
|
||||||
|
@ -531,7 +578,12 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Overlays::isLoaded(OverlayID id) {
|
bool Overlays::isLoaded(OverlayID id) {
|
||||||
QReadLocker lock(&_lock);
|
if (QThread::currentThread() != thread()) {
|
||||||
|
bool result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "isLoaded", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay::Pointer thisOverlay = getOverlay(id);
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
if (!thisOverlay) {
|
if (!thisOverlay) {
|
||||||
return false; // not found
|
return false; // not found
|
||||||
|
@ -539,7 +591,13 @@ bool Overlays::isLoaded(OverlayID id) {
|
||||||
return thisOverlay->isLoaded();
|
return thisOverlay->isLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSizeF Overlays::textSize(OverlayID id, const QString& text) const {
|
QSizeF Overlays::textSize(OverlayID id, const QString& text) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QSizeF result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "textSize", Q_RETURN_ARG(QSizeF, result), Q_ARG(OverlayID, id), Q_ARG(QString, text));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay::Pointer thisOverlay = _overlaysHUD[id];
|
Overlay::Pointer thisOverlay = _overlaysHUD[id];
|
||||||
if (thisOverlay) {
|
if (thisOverlay) {
|
||||||
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
|
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
|
||||||
|
@ -554,6 +612,7 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) const {
|
||||||
return QSizeF(0.0f, 0.0f);
|
return QSizeF(0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OVERLAY_PANELS
|
||||||
OverlayID Overlays::addPanel(OverlayPanel::Pointer panel) {
|
OverlayID Overlays::addPanel(OverlayPanel::Pointer panel) {
|
||||||
QWriteLocker lock(&_lock);
|
QWriteLocker lock(&_lock);
|
||||||
|
|
||||||
|
@ -607,8 +666,15 @@ void Overlays::deletePanel(OverlayID panelId) {
|
||||||
|
|
||||||
emit panelDeleted(panelId);
|
emit panelDeleted(panelId);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool Overlays::isAddedOverlay(OverlayID id) {
|
bool Overlays::isAddedOverlay(OverlayID id) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
bool result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "isAddedOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
|
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,20 +702,43 @@ void Overlays::sendHoverLeaveOverlay(OverlayID id, PointerEvent event) {
|
||||||
emit hoverLeaveOverlay(id, event);
|
emit hoverLeaveOverlay(id, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayID Overlays::getKeyboardFocusOverlay() const {
|
OverlayID Overlays::getKeyboardFocusOverlay() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
OverlayID result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "getKeyboardFocusOverlay", Q_RETURN_ARG(OverlayID, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
return qApp->getKeyboardFocusOverlay();
|
return qApp->getKeyboardFocusOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::setKeyboardFocusOverlay(OverlayID id) {
|
void Overlays::setKeyboardFocusOverlay(OverlayID id) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setKeyboardFocusOverlay", Q_ARG(OverlayID, id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qApp->setKeyboardFocusOverlay(id);
|
qApp->setKeyboardFocusOverlay(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Overlays::width() const {
|
float Overlays::width() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
float result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "width", Q_RETURN_ARG(float, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
return offscreenUi->getWindow()->size().width();
|
return offscreenUi->getWindow()->size().width();
|
||||||
}
|
}
|
||||||
|
|
||||||
float Overlays::height() const {
|
float Overlays::height() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
float result;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "height", Q_RETURN_ARG(float, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
return offscreenUi->getWindow()->size().height();
|
return offscreenUi->getWindow()->size().height();
|
||||||
}
|
}
|
||||||
|
@ -705,7 +794,6 @@ PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay r
|
||||||
|
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlay);
|
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlay);
|
||||||
|
|
||||||
QReadLocker lock(&_lock);
|
|
||||||
auto position = thisOverlay->getPosition();
|
auto position = thisOverlay->getPosition();
|
||||||
auto rotation = thisOverlay->getRotation();
|
auto rotation = thisOverlay->getRotation();
|
||||||
auto dimensions = thisOverlay->getSize();
|
auto dimensions = thisOverlay->getSize();
|
||||||
|
@ -854,8 +942,13 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) const {
|
QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
|
||||||
QVector<QUuid> result;
|
QVector<QUuid> result;
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "findOverlays", Q_RETURN_ARG(QVector<QUuid>, result), Q_ARG(glm::vec3, center), Q_ARG(float, radius));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
|
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
|
||||||
int checked = 0;
|
int checked = 0;
|
||||||
|
|
|
@ -25,8 +25,9 @@
|
||||||
#include <PointerEvent.h>
|
#include <PointerEvent.h>
|
||||||
|
|
||||||
#include "Overlay.h"
|
#include "Overlay.h"
|
||||||
#include "OverlayPanel.h"
|
|
||||||
#include "PanelAttachable.h"
|
#include "PanelAttachable.h"
|
||||||
|
#include "OverlayPanel.h"
|
||||||
|
|
||||||
class PickRay;
|
class PickRay;
|
||||||
|
|
||||||
|
@ -41,6 +42,8 @@ Q_DECLARE_METATYPE(OverlayPropertyResult);
|
||||||
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value);
|
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value);
|
||||||
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value);
|
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value);
|
||||||
|
|
||||||
|
const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* @typedef Overlays.RayToOverlayIntersectionResult
|
* @typedef Overlays.RayToOverlayIntersectionResult
|
||||||
* @property {bool} intersects True if the PickRay intersected with a 3D overlay.
|
* @property {bool} intersects True if the PickRay intersected with a 3D overlay.
|
||||||
|
@ -51,10 +54,9 @@ void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPro
|
||||||
*/
|
*/
|
||||||
class RayToOverlayIntersectionResult {
|
class RayToOverlayIntersectionResult {
|
||||||
public:
|
public:
|
||||||
RayToOverlayIntersectionResult();
|
bool intersects { false };
|
||||||
bool intersects;
|
OverlayID overlayID { UNKNOWN_OVERLAY_ID };
|
||||||
OverlayID overlayID;
|
float distance { 0 };
|
||||||
float distance;
|
|
||||||
BoxFace face;
|
BoxFace face;
|
||||||
glm::vec3 surfaceNormal;
|
glm::vec3 surfaceNormal;
|
||||||
glm::vec3 intersection;
|
glm::vec3 intersection;
|
||||||
|
@ -77,8 +79,6 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
|
||||||
* @namespace Overlays
|
* @namespace Overlays
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const OverlayID UNKNOWN_OVERLAY_ID = OverlayID();
|
|
||||||
|
|
||||||
class Overlays : public QObject {
|
class Overlays : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -94,11 +94,13 @@ public:
|
||||||
void enable();
|
void enable();
|
||||||
|
|
||||||
Overlay::Pointer getOverlay(OverlayID id) const;
|
Overlay::Pointer getOverlay(OverlayID id) const;
|
||||||
|
#if OVERLAY_PANELS
|
||||||
OverlayPanel::Pointer getPanel(OverlayID id) const { return _panels[id]; }
|
OverlayPanel::Pointer getPanel(OverlayID id) const { return _panels[id]; }
|
||||||
|
#endif
|
||||||
|
|
||||||
/// adds an overlay that's already been created
|
/// adds an overlay that's already been created
|
||||||
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
|
OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); }
|
||||||
OverlayID addOverlay(Overlay::Pointer overlay);
|
OverlayID addOverlay(const Overlay::Pointer& overlay);
|
||||||
|
|
||||||
bool mousePressEvent(QMouseEvent* event);
|
bool mousePressEvent(QMouseEvent* event);
|
||||||
bool mouseDoublePressEvent(QMouseEvent* event);
|
bool mouseDoublePressEvent(QMouseEvent* event);
|
||||||
|
@ -156,7 +158,7 @@ public slots:
|
||||||
* @param {Overlays.OverlayID} overlayID The ID of the overlay to get the type of.
|
* @param {Overlays.OverlayID} overlayID The ID of the overlay to get the type of.
|
||||||
* @return {string} The type of the overlay if found, otherwise the empty string.
|
* @return {string} The type of the overlay if found, otherwise the empty string.
|
||||||
*/
|
*/
|
||||||
QString getOverlayType(OverlayID overlayId) const;
|
QString getOverlayType(OverlayID overlayId);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Get the overlay Script object.
|
* Get the overlay Script object.
|
||||||
|
@ -215,7 +217,7 @@ public slots:
|
||||||
* @param {float} radius search radius
|
* @param {float} radius search radius
|
||||||
* @return {Overlays.OverlayID[]} list of overlays withing the radius
|
* @return {Overlays.OverlayID[]} list of overlays withing the radius
|
||||||
*/
|
*/
|
||||||
QVector<QUuid> findOverlays(const glm::vec3& center, float radius) const;
|
QVector<QUuid> findOverlays(const glm::vec3& center, float radius);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Check whether an overlay's assets have been loaded. For example, if the
|
* Check whether an overlay's assets have been loaded. For example, if the
|
||||||
|
@ -237,7 +239,7 @@ public slots:
|
||||||
* @param {string} The string to measure.
|
* @param {string} The string to measure.
|
||||||
* @return {Vec2} The size of the text.
|
* @return {Vec2} The size of the text.
|
||||||
*/
|
*/
|
||||||
QSizeF textSize(OverlayID id, const QString& text) const;
|
QSizeF textSize(OverlayID id, const QString& text);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Get the width of the virtual 2D HUD.
|
* Get the width of the virtual 2D HUD.
|
||||||
|
@ -245,7 +247,7 @@ public slots:
|
||||||
* @function Overlays.width
|
* @function Overlays.width
|
||||||
* @return {float} The width of the 2D HUD.
|
* @return {float} The width of the 2D HUD.
|
||||||
*/
|
*/
|
||||||
float width() const;
|
float width();
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Get the height of the virtual 2D HUD.
|
* Get the height of the virtual 2D HUD.
|
||||||
|
@ -253,11 +255,12 @@ public slots:
|
||||||
* @function Overlays.height
|
* @function Overlays.height
|
||||||
* @return {float} The height of the 2D HUD.
|
* @return {float} The height of the 2D HUD.
|
||||||
*/
|
*/
|
||||||
float height() const;
|
float height();
|
||||||
|
|
||||||
/// return true if there is an overlay with that id else false
|
/// return true if there is an overlay with that id else false
|
||||||
bool isAddedOverlay(OverlayID id);
|
bool isAddedOverlay(OverlayID id);
|
||||||
|
|
||||||
|
#if OVERLAY_PANELS
|
||||||
OverlayID getParentPanel(OverlayID childId) const;
|
OverlayID getParentPanel(OverlayID childId) const;
|
||||||
void setParentPanel(OverlayID childId, OverlayID panelId);
|
void setParentPanel(OverlayID childId, OverlayID panelId);
|
||||||
|
|
||||||
|
@ -279,6 +282,8 @@ public slots:
|
||||||
/// return true if there is a panel with that id else false
|
/// return true if there is a panel with that id else false
|
||||||
bool isAddedPanel(OverlayID id) { return _panels.contains(id); }
|
bool isAddedPanel(OverlayID id) { return _panels.contains(id); }
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void sendMouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void sendMouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
void sendMouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void sendMouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
||||||
|
@ -287,7 +292,7 @@ public slots:
|
||||||
void sendHoverOverOverlay(OverlayID id, PointerEvent event);
|
void sendHoverOverOverlay(OverlayID id, PointerEvent event);
|
||||||
void sendHoverLeaveOverlay(OverlayID id, PointerEvent event);
|
void sendHoverLeaveOverlay(OverlayID id, PointerEvent event);
|
||||||
|
|
||||||
OverlayID getKeyboardFocusOverlay() const;
|
OverlayID getKeyboardFocusOverlay();
|
||||||
void setKeyboardFocusOverlay(OverlayID id);
|
void setKeyboardFocusOverlay(OverlayID id);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
@ -316,13 +321,15 @@ private:
|
||||||
|
|
||||||
QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
|
QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
|
||||||
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
|
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
|
||||||
|
#if OVERLAY_PANELS
|
||||||
QMap<OverlayID, OverlayPanel::Pointer> _panels;
|
QMap<OverlayID, OverlayPanel::Pointer> _panels;
|
||||||
|
#endif
|
||||||
QList<Overlay::Pointer> _overlaysToDelete;
|
QList<Overlay::Pointer> _overlaysToDelete;
|
||||||
unsigned int _stackOrder { 1 };
|
unsigned int _stackOrder { 1 };
|
||||||
|
|
||||||
QReadWriteLock _lock;
|
#if OVERLAY_PANELS
|
||||||
QReadWriteLock _deleteLock;
|
|
||||||
QScriptEngine* _scriptEngine;
|
QScriptEngine* _scriptEngine;
|
||||||
|
#endif
|
||||||
bool _enabled = true;
|
bool _enabled = true;
|
||||||
|
|
||||||
PointerEvent calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, RayToOverlayIntersectionResult rayPickResult,
|
PointerEvent calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, RayToOverlayIntersectionResult rayPickResult,
|
||||||
|
@ -331,7 +338,7 @@ private:
|
||||||
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
|
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
|
||||||
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
|
OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID };
|
||||||
|
|
||||||
RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking,
|
Q_INVOKABLE RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking,
|
||||||
const QVector<OverlayID>& overlaysToInclude,
|
const QVector<OverlayID>& overlaysToInclude,
|
||||||
const QVector<OverlayID>& overlaysToDiscard,
|
const QVector<OverlayID>& overlaysToDiscard,
|
||||||
bool visibleOnly = false, bool collidableOnly = false);
|
bool visibleOnly = false, bool collidableOnly = false);
|
||||||
|
|
|
@ -16,11 +16,15 @@
|
||||||
#include "OverlayPanel.h"
|
#include "OverlayPanel.h"
|
||||||
|
|
||||||
bool PanelAttachable::getParentVisible() const {
|
bool PanelAttachable::getParentVisible() const {
|
||||||
|
#if OVERLAY_PANELS
|
||||||
if (getParentPanel()) {
|
if (getParentPanel()) {
|
||||||
return getParentPanel()->getVisible() && getParentPanel()->getParentVisible();
|
return getParentPanel()->getVisible() && getParentPanel()->getParentVisible();
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant PanelAttachable::getProperty(const QString& property) {
|
QVariant PanelAttachable::getProperty(const QString& property) {
|
||||||
|
@ -61,11 +65,13 @@ void PanelAttachable::applyTransformTo(Transform& transform, bool force) {
|
||||||
if (force || usecTimestampNow() > _transformExpiry) {
|
if (force || usecTimestampNow() > _transformExpiry) {
|
||||||
const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz
|
const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz
|
||||||
_transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD;
|
_transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD;
|
||||||
|
#if OVERLAY_PANELS
|
||||||
if (getParentPanel()) {
|
if (getParentPanel()) {
|
||||||
getParentPanel()->applyTransformTo(transform, true);
|
getParentPanel()->applyTransformTo(transform, true);
|
||||||
transform.postTranslate(getOffsetPosition());
|
transform.postTranslate(getOffsetPosition());
|
||||||
transform.postRotate(getOffsetRotation());
|
transform.postRotate(getOffsetRotation());
|
||||||
transform.postScale(getOffsetScale());
|
transform.postScale(getOffsetScale());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#ifndef hifi_PanelAttachable_h
|
#ifndef hifi_PanelAttachable_h
|
||||||
#define hifi_PanelAttachable_h
|
#define hifi_PanelAttachable_h
|
||||||
|
|
||||||
|
#define OVERLAY_PANELS 0
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
@ -39,18 +41,21 @@
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
class OverlayPanel;
|
class OverlayPanel;
|
||||||
|
|
||||||
class PanelAttachable {
|
class PanelAttachable {
|
||||||
public:
|
public:
|
||||||
// getters
|
// getters
|
||||||
|
#if OVERLAY_PANELS
|
||||||
std::shared_ptr<OverlayPanel> getParentPanel() const { return _parentPanel; }
|
std::shared_ptr<OverlayPanel> getParentPanel() const { return _parentPanel; }
|
||||||
|
#endif
|
||||||
glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); }
|
glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); }
|
||||||
glm::quat getOffsetRotation() const { return _offset.getRotation(); }
|
glm::quat getOffsetRotation() const { return _offset.getRotation(); }
|
||||||
glm::vec3 getOffsetScale() const { return _offset.getScale(); }
|
glm::vec3 getOffsetScale() const { return _offset.getScale(); }
|
||||||
bool getParentVisible() const;
|
bool getParentVisible() const;
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
|
#if OVERLAY_PANELS
|
||||||
void setParentPanel(std::shared_ptr<OverlayPanel> panel) { _parentPanel = panel; }
|
void setParentPanel(std::shared_ptr<OverlayPanel> panel) { _parentPanel = panel; }
|
||||||
|
#endif
|
||||||
void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); }
|
void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); }
|
||||||
void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); }
|
void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); }
|
||||||
void setOffsetScale(float scale) { _offset.setScale(scale); }
|
void setOffsetScale(float scale) { _offset.setScale(scale); }
|
||||||
|
@ -66,7 +71,9 @@ protected:
|
||||||
quint64 _transformExpiry = 0;
|
quint64 _transformExpiry = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
#if OVERLAY_PANELS
|
||||||
std::shared_ptr<OverlayPanel> _parentPanel = nullptr;
|
std::shared_ptr<OverlayPanel> _parentPanel = nullptr;
|
||||||
|
#endif
|
||||||
Transform _offset;
|
Transform _offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -32,21 +32,20 @@ QmlOverlay::QmlOverlay(const QUrl& url, const QmlOverlay* textOverlay)
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlOverlay::buildQmlElement(const QUrl& url) {
|
void QmlOverlay::buildQmlElement(const QUrl& url) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "buildQmlElement", Q_ARG(QUrl, url));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->returnFromUiThread([=] {
|
offscreenUi->load(url, [=](QQmlContext* context, QObject* object) {
|
||||||
offscreenUi->load(url, [=](QQmlContext* context, QObject* object) {
|
QQuickItem* rawPtr = dynamic_cast<QQuickItem*>(object);
|
||||||
QQuickItem* rawPtr = dynamic_cast<QQuickItem*>(object);
|
// Create a shared ptr with a custom deleter lambda, that calls deleteLater
|
||||||
// Create a shared ptr with a custom deleter lambda, that calls deleteLater
|
_qmlElement = std::shared_ptr<QQuickItem>(rawPtr, [](QQuickItem* ptr) {
|
||||||
_qmlElement = std::shared_ptr<QQuickItem>(rawPtr, [](QQuickItem* ptr) {
|
if (ptr) {
|
||||||
if (ptr) {
|
ptr->deleteLater();
|
||||||
ptr->deleteLater();
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
while (!_qmlElement) {
|
|
||||||
qApp->processEvents();
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,20 +54,23 @@ QmlOverlay::~QmlOverlay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlOverlay::setProperties(const QVariantMap& properties) {
|
void QmlOverlay::setProperties(const QVariantMap& properties) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setProperties", Q_ARG(QVariantMap, properties));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Overlay2D::setProperties(properties);
|
Overlay2D::setProperties(properties);
|
||||||
auto bounds = _bounds;
|
auto bounds = _bounds;
|
||||||
std::weak_ptr<QQuickItem> weakQmlElement = _qmlElement;
|
std::weak_ptr<QQuickItem> weakQmlElement = _qmlElement;
|
||||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([weakQmlElement, bounds, properties] {
|
// check to see if qmlElement still exists
|
||||||
// check to see if qmlElement still exists
|
auto qmlElement = weakQmlElement.lock();
|
||||||
auto qmlElement = weakQmlElement.lock();
|
if (qmlElement) {
|
||||||
if (qmlElement) {
|
qmlElement->setX(bounds.left());
|
||||||
qmlElement->setX(bounds.left());
|
qmlElement->setY(bounds.top());
|
||||||
qmlElement->setY(bounds.top());
|
qmlElement->setWidth(bounds.width());
|
||||||
qmlElement->setWidth(bounds.width());
|
qmlElement->setHeight(bounds.height());
|
||||||
qmlElement->setHeight(bounds.height());
|
QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties));
|
||||||
QMetaObject::invokeMethod(qmlElement.get(), "updatePropertiesFromScript", Qt::DirectConnection, Q_ARG(QVariant, properties));
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlOverlay::render(RenderArgs* args) {
|
void QmlOverlay::render(RenderArgs* args) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ public:
|
||||||
void render(RenderArgs* args) override;
|
void render(RenderArgs* args) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void buildQmlElement(const QUrl& url);
|
Q_INVOKABLE void buildQmlElement(const QUrl& url);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<QQuickItem> _qmlElement;
|
std::shared_ptr<QQuickItem> _qmlElement;
|
||||||
|
|
|
@ -259,10 +259,21 @@ void AudioClient::customDeleter() {
|
||||||
void AudioClient::cleanupBeforeQuit() {
|
void AudioClient::cleanupBeforeQuit() {
|
||||||
// FIXME: this should be put in customDeleter, but there is still a reference to this when it is called,
|
// FIXME: this should be put in customDeleter, but there is still a reference to this when it is called,
|
||||||
// so this must be explicitly, synchronously stopped
|
// so this must be explicitly, synchronously stopped
|
||||||
|
static ConditionalGuard guard;
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
// This will likely be called from the main thread, but we don't want to do blocking queued calls
|
||||||
|
// from the main thread, so we use a normal auto-connection invoke, and then use a conditional to wait
|
||||||
|
// for completion
|
||||||
|
// The effect is the same, yes, but we actually want to avoid the use of Qt::BlockingQueuedConnection
|
||||||
|
// in the code
|
||||||
|
QMetaObject::invokeMethod(this, "cleanupBeforeQuit");
|
||||||
|
guard.wait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
_checkDevicesTimer->stop();
|
_checkDevicesTimer->stop();
|
||||||
|
guard.trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) {
|
void AudioClient::handleMismatchAudioFormat(SharedNodePointer node, const QString& currentCodec, const QString& recievedCodec) {
|
||||||
|
@ -1859,7 +1870,7 @@ void AudioClient::startThread() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioClient::setInputVolume(float volume) {
|
void AudioClient::setInputVolume(float volume) {
|
||||||
if (_audioInput && volume != _audioInput->volume()) {
|
if (_audioInput && volume != (float)_audioInput->volume()) {
|
||||||
_audioInput->setVolume(volume);
|
_audioInput->setVolume(volume);
|
||||||
emit inputVolumeChanged(_audioInput->volume());
|
emit inputVolumeChanged(_audioInput->volume());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <QtScript/QScriptContext>
|
#include <QtScript/QScriptContext>
|
||||||
#include <QtScript/QScriptEngine>
|
#include <QtScript/QScriptEngine>
|
||||||
|
|
||||||
|
#include <shared/QtHelpers.h>
|
||||||
#include "OffscreenUi.h"
|
#include "OffscreenUi.h"
|
||||||
|
|
||||||
static const char* const URL_PROPERTY = "source";
|
static const char* const URL_PROPERTY = "source";
|
||||||
|
@ -21,39 +22,51 @@ static const char* const SCRIPT_PROPERTY = "scriptUrl";
|
||||||
// Method called by Qt scripts to create a new web window in the overlay
|
// Method called by Qt scripts to create a new web window in the overlay
|
||||||
QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
QScriptValue QmlWebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||||
auto properties = parseArguments(context);
|
auto properties = parseArguments(context);
|
||||||
QmlWebWindowClass* retVal { nullptr };
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->executeOnUiThread([&] {
|
QmlWebWindowClass* retVal = new QmlWebWindowClass();
|
||||||
retVal = new QmlWebWindowClass();
|
|
||||||
retVal->initQml(properties);
|
|
||||||
}, true);
|
|
||||||
Q_ASSERT(retVal);
|
Q_ASSERT(retVal);
|
||||||
|
if (QThread::currentThread() != qApp->thread()) {
|
||||||
|
retVal->moveToThread(qApp->thread());
|
||||||
|
QMetaObject::invokeMethod(retVal, "initQml", Q_ARG(QVariantMap, properties));
|
||||||
|
} else {
|
||||||
|
retVal->initQml(properties);
|
||||||
|
}
|
||||||
connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater);
|
connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater);
|
||||||
return engine->newQObject(retVal);
|
return engine->newQObject(retVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QmlWebWindowClass::getURL() const {
|
QString QmlWebWindowClass::getURL() {
|
||||||
QVariant result = DependencyManager::get<OffscreenUi>()->returnFromUiThread([&]()->QVariant {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (_qmlWindow.isNull()) {
|
QString result = false;
|
||||||
return QVariant();
|
hifi::qt::blockingInvokeMethod(this, "getURL", Q_RETURN_ARG(QString, result));
|
||||||
}
|
return result;
|
||||||
return _qmlWindow->property(URL_PROPERTY);
|
}
|
||||||
});
|
|
||||||
return result.toString();
|
if (_qmlWindow.isNull()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _qmlWindow->property(URL_PROPERTY).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWebWindowClass::setURL(const QString& urlString) {
|
void QmlWebWindowClass::setURL(const QString& urlString) {
|
||||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (!_qmlWindow.isNull()) {
|
QMetaObject::invokeMethod(this, "setURL", Q_ARG(QString, urlString));
|
||||||
_qmlWindow->setProperty(URL_PROPERTY, urlString);
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
if (!_qmlWindow.isNull()) {
|
||||||
|
_qmlWindow->setProperty(URL_PROPERTY, urlString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWebWindowClass::setScriptURL(const QString& script) {
|
void QmlWebWindowClass::setScriptURL(const QString& script) {
|
||||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (!_qmlWindow.isNull()) {
|
QMetaObject::invokeMethod(this, "setScriptURL", Q_ARG(QString, script));
|
||||||
_qmlWindow->setProperty(SCRIPT_PROPERTY, script);
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
if (!_qmlWindow.isNull()) {
|
||||||
|
_qmlWindow->setProperty(SCRIPT_PROPERTY, script);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ public:
|
||||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
QString getURL() const;
|
QString getURL();
|
||||||
void setURL(const QString& url);
|
void setURL(const QString& url);
|
||||||
void setScriptURL(const QString& script);
|
void setScriptURL(const QString& script);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <QtCore/QJsonDocument>
|
#include <QtCore/QJsonDocument>
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
|
|
||||||
|
#include <shared/QtHelpers.h>
|
||||||
#include "OffscreenUi.h"
|
#include "OffscreenUi.h"
|
||||||
|
|
||||||
static const char* const SOURCE_PROPERTY = "source";
|
static const char* const SOURCE_PROPERTY = "source";
|
||||||
|
@ -73,13 +74,15 @@ QVariantMap QmlWindowClass::parseArguments(QScriptContext* context) {
|
||||||
// Method called by Qt scripts to create a new web window in the overlay
|
// Method called by Qt scripts to create a new web window in the overlay
|
||||||
QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
QScriptValue QmlWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) {
|
||||||
auto properties = parseArguments(context);
|
auto properties = parseArguments(context);
|
||||||
QmlWindowClass* retVal { nullptr };
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->executeOnUiThread([&] {
|
QmlWindowClass* retVal = new QmlWindowClass();
|
||||||
retVal = new QmlWindowClass();
|
|
||||||
retVal->initQml(properties);
|
|
||||||
}, true);
|
|
||||||
Q_ASSERT(retVal);
|
Q_ASSERT(retVal);
|
||||||
|
if (QThread::currentThread() != qApp->thread()) {
|
||||||
|
retVal->moveToThread(qApp->thread());
|
||||||
|
hifi::qt::blockingInvokeMethod(retVal, "initQml", Q_ARG(QVariantMap, properties));
|
||||||
|
} else {
|
||||||
|
retVal->initQml(properties);
|
||||||
|
}
|
||||||
connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater);
|
connect(engine, &QScriptEngine::destroyed, retVal, &QmlWindowClass::deleteLater);
|
||||||
return engine->newQObject(retVal);
|
return engine->newQObject(retVal);
|
||||||
}
|
}
|
||||||
|
@ -214,49 +217,64 @@ QQuickItem* QmlWindowClass::asQuickItem() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWindowClass::setVisible(bool visible) {
|
void QmlWindowClass::setVisible(bool visible) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setVisible", Q_ARG(bool, visible));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QQuickItem* targetWindow = asQuickItem();
|
QQuickItem* targetWindow = asQuickItem();
|
||||||
if (_toolWindow) {
|
if (_toolWindow) {
|
||||||
// For tool window tabs we special case visibility as a function call on the tab parent
|
// For tool window tabs we special case visibility as a function call on the tab parent
|
||||||
// The tool window itself has special logic based on whether any tabs are visible
|
// The tool window itself has special logic based on whether any tabs are visible
|
||||||
QMetaObject::invokeMethod(targetWindow, "showTabForUrl", Qt::QueuedConnection, Q_ARG(QVariant, _source), Q_ARG(QVariant, visible));
|
QMetaObject::invokeMethod(targetWindow, "showTabForUrl", Qt::QueuedConnection, Q_ARG(QVariant, _source), Q_ARG(QVariant, visible));
|
||||||
} else {
|
} else {
|
||||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
targetWindow->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, visible);
|
||||||
targetWindow->setProperty(OFFSCREEN_VISIBILITY_PROPERTY, visible);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QmlWindowClass::isVisible() const {
|
bool QmlWindowClass::isVisible() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
bool result = false;
|
||||||
|
hifi::qt::blockingInvokeMethod(this, "isVisible", Q_RETURN_ARG(bool, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// The tool window itself has special logic based on whether any tabs are enabled
|
// The tool window itself has special logic based on whether any tabs are enabled
|
||||||
return DependencyManager::get<OffscreenUi>()->returnFromUiThread([&] {
|
if (_qmlWindow.isNull()) {
|
||||||
if (_qmlWindow.isNull()) {
|
return false;
|
||||||
return QVariant::fromValue(false);
|
}
|
||||||
}
|
|
||||||
if (_toolWindow) {
|
if (_toolWindow) {
|
||||||
return QVariant::fromValue(dynamic_cast<QQuickItem*>(_qmlWindow.data())->isEnabled());
|
return dynamic_cast<QQuickItem*>(_qmlWindow.data())->isEnabled();
|
||||||
} else {
|
}
|
||||||
return QVariant::fromValue(asQuickItem()->isVisible());
|
|
||||||
}
|
return asQuickItem()->isVisible();
|
||||||
}).toBool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 QmlWindowClass::getPosition() const {
|
glm::vec2 QmlWindowClass::getPosition() {
|
||||||
QVariant result = DependencyManager::get<OffscreenUi>()->returnFromUiThread([&]()->QVariant {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (_qmlWindow.isNull()) {
|
vec2 result;
|
||||||
return QVariant(QPointF(0, 0));
|
hifi::qt::blockingInvokeMethod(this, "getPosition", Q_RETURN_ARG(vec2, result));
|
||||||
}
|
return result;
|
||||||
return asQuickItem()->position();
|
}
|
||||||
});
|
|
||||||
return toGlm(result.toPointF());
|
if (_qmlWindow.isNull()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return toGlm(asQuickItem()->position());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void QmlWindowClass::setPosition(const glm::vec2& position) {
|
void QmlWindowClass::setPosition(const glm::vec2& position) {
|
||||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (!_qmlWindow.isNull()) {
|
QMetaObject::invokeMethod(this, "setPosition", Q_ARG(vec2, position));
|
||||||
asQuickItem()->setPosition(QPointF(position.x, position.y));
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
if (!_qmlWindow.isNull()) {
|
||||||
|
asQuickItem()->setPosition(QPointF(position.x, position.y));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWindowClass::setPosition(int x, int y) {
|
void QmlWindowClass::setPosition(int x, int y) {
|
||||||
|
@ -268,23 +286,29 @@ glm::vec2 toGlm(const QSizeF& size) {
|
||||||
return glm::vec2(size.width(), size.height());
|
return glm::vec2(size.width(), size.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 QmlWindowClass::getSize() const {
|
glm::vec2 QmlWindowClass::getSize() {
|
||||||
QVariant result = DependencyManager::get<OffscreenUi>()->returnFromUiThread([&]()->QVariant {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (_qmlWindow.isNull()) {
|
vec2 result;
|
||||||
return QVariant(QSizeF(0, 0));
|
hifi::qt::blockingInvokeMethod(this, "getSize", Q_RETURN_ARG(vec2, result));
|
||||||
}
|
return result;
|
||||||
QQuickItem* targetWindow = asQuickItem();
|
}
|
||||||
return QSizeF(targetWindow->width(), targetWindow->height());
|
|
||||||
});
|
if (_qmlWindow.isNull()) {
|
||||||
return toGlm(result.toSizeF());
|
return {};
|
||||||
|
}
|
||||||
|
QQuickItem* targetWindow = asQuickItem();
|
||||||
|
return vec2(targetWindow->width(), targetWindow->height());
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWindowClass::setSize(const glm::vec2& size) {
|
void QmlWindowClass::setSize(const glm::vec2& size) {
|
||||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (!_qmlWindow.isNull()) {
|
QMetaObject::invokeMethod(this, "setSize", Q_ARG(vec2, size));
|
||||||
asQuickItem()->setSize(QSizeF(size.x, size.y));
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
if (!_qmlWindow.isNull()) {
|
||||||
|
asQuickItem()->setSize(QSizeF(size.x, size.y));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWindowClass::setSize(int width, int height) {
|
void QmlWindowClass::setSize(int width, int height) {
|
||||||
|
@ -292,28 +316,33 @@ void QmlWindowClass::setSize(int width, int height) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWindowClass::setTitle(const QString& title) {
|
void QmlWindowClass::setTitle(const QString& title) {
|
||||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (!_qmlWindow.isNull()) {
|
QMetaObject::invokeMethod(this, "setTitle", Q_ARG(QString, title));
|
||||||
asQuickItem()->setProperty(TITLE_PROPERTY, title);
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
if (!_qmlWindow.isNull()) {
|
||||||
|
asQuickItem()->setProperty(TITLE_PROPERTY, title);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWindowClass::close() {
|
void QmlWindowClass::close() {
|
||||||
if (_qmlWindow) {
|
if (QThread::currentThread() != thread()) {
|
||||||
if (_toolWindow) {
|
QMetaObject::invokeMethod(this, "close");
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
return;
|
||||||
offscreenUi->executeOnUiThread([=] {
|
|
||||||
auto toolWindow = offscreenUi->getToolWindow();
|
|
||||||
auto invokeResult = QMetaObject::invokeMethod(toolWindow, "removeTabForUrl", Qt::DirectConnection,
|
|
||||||
Q_ARG(QVariant, _source));
|
|
||||||
Q_ASSERT(invokeResult);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
_qmlWindow->deleteLater();
|
|
||||||
}
|
|
||||||
_qmlWindow = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_toolWindow) {
|
||||||
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
|
auto toolWindow = offscreenUi->getToolWindow();
|
||||||
|
auto invokeResult = QMetaObject::invokeMethod(toolWindow, "removeTabForUrl", Qt::DirectConnection,
|
||||||
|
Q_ARG(QVariant, _source));
|
||||||
|
Q_ASSERT(invokeResult);
|
||||||
|
return;
|
||||||
|
} else if (_qmlWindow) {
|
||||||
|
_qmlWindow->deleteLater();
|
||||||
|
}
|
||||||
|
_qmlWindow = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWindowClass::hasMoved(QVector2D position) {
|
void QmlWindowClass::hasMoved(QVector2D position) {
|
||||||
|
@ -325,10 +354,13 @@ void QmlWindowClass::hasClosed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlWindowClass::raise() {
|
void QmlWindowClass::raise() {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "raise");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->executeOnUiThread([=] {
|
if (_qmlWindow) {
|
||||||
if (!_qmlWindow.isNull()) {
|
QMetaObject::invokeMethod(asQuickItem(), "raise", Qt::DirectConnection);
|
||||||
QMetaObject::invokeMethod(asQuickItem(), "raise", Qt::DirectConnection);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,18 +31,18 @@ public:
|
||||||
QmlWindowClass();
|
QmlWindowClass();
|
||||||
~QmlWindowClass();
|
~QmlWindowClass();
|
||||||
|
|
||||||
virtual void initQml(QVariantMap properties);
|
Q_INVOKABLE virtual void initQml(QVariantMap properties);
|
||||||
QQuickItem* asQuickItem() const;
|
QQuickItem* asQuickItem() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool isVisible() const;
|
bool isVisible();
|
||||||
void setVisible(bool visible);
|
void setVisible(bool visible);
|
||||||
|
|
||||||
glm::vec2 getPosition() const;
|
glm::vec2 getPosition();
|
||||||
void setPosition(const glm::vec2& position);
|
void setPosition(const glm::vec2& position);
|
||||||
void setPosition(int x, int y);
|
void setPosition(int x, int y);
|
||||||
|
|
||||||
glm::vec2 getSize() const;
|
glm::vec2 getSize();
|
||||||
void setSize(const glm::vec2& size);
|
void setSize(const glm::vec2& size);
|
||||||
void setSize(int width, int height);
|
void setSize(int width, int height);
|
||||||
void setTitle(const QString& title);
|
void setTitle(const QString& title);
|
||||||
|
|
|
@ -887,28 +887,6 @@ QQmlContext* OffscreenQmlSurface::getSurfaceContext() {
|
||||||
return _qmlContext;
|
return _qmlContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenQmlSurface::executeOnUiThread(std::function<void()> function, bool blocking ) {
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
QMetaObject::invokeMethod(this, "executeOnUiThread", blocking ? Qt::BlockingQueuedConnection : Qt::QueuedConnection,
|
|
||||||
Q_ARG(std::function<void()>, function));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
function();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant OffscreenQmlSurface::returnFromUiThread(std::function<QVariant()> function) {
|
|
||||||
if (QThread::currentThread() != thread()) {
|
|
||||||
QVariant result;
|
|
||||||
hifi::qt::blockingInvokeMethod(this, "returnFromUiThread",
|
|
||||||
Q_RETURN_ARG(QVariant, result),
|
|
||||||
Q_ARG(std::function<QVariant()>, function));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return function();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OffscreenQmlSurface::focusDestroyed(QObject *obj) {
|
void OffscreenQmlSurface::focusDestroyed(QObject *obj) {
|
||||||
_currentFocusItem = nullptr;
|
_currentFocusItem = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,10 +55,6 @@ public:
|
||||||
return load(QUrl(qmlSourceFile), f);
|
return load(QUrl(qmlSourceFile), f);
|
||||||
}
|
}
|
||||||
void clearCache();
|
void clearCache();
|
||||||
|
|
||||||
Q_INVOKABLE void executeOnUiThread(std::function<void()> function, bool blocking = false);
|
|
||||||
Q_INVOKABLE QVariant returnFromUiThread(std::function<QVariant()> function);
|
|
||||||
|
|
||||||
void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; }
|
void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; }
|
||||||
// Optional values for event handling
|
// Optional values for event handling
|
||||||
void setProxyWindow(QWindow* window);
|
void setProxyWindow(QWindow* window);
|
||||||
|
|
|
@ -214,20 +214,18 @@ void TabletProxy::setToolbarMode(bool toolbarMode) {
|
||||||
|
|
||||||
// create new desktop window
|
// create new desktop window
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->executeOnUiThread([=] {
|
auto tabletRootWindow = new TabletRootWindow();
|
||||||
auto tabletRootWindow = new TabletRootWindow();
|
tabletRootWindow->initQml(QVariantMap());
|
||||||
tabletRootWindow->initQml(QVariantMap());
|
auto quickItem = tabletRootWindow->asQuickItem();
|
||||||
auto quickItem = tabletRootWindow->asQuickItem();
|
_desktopWindow = tabletRootWindow;
|
||||||
_desktopWindow = tabletRootWindow;
|
QMetaObject::invokeMethod(quickItem, "setShown", Q_ARG(const QVariant&, QVariant(false)));
|
||||||
QMetaObject::invokeMethod(quickItem, "setShown", Q_ARG(const QVariant&, QVariant(false)));
|
|
||||||
|
|
||||||
QObject::connect(quickItem, SIGNAL(windowClosed()), this, SLOT(desktopWindowClosed()));
|
QObject::connect(quickItem, SIGNAL(windowClosed()), this, SLOT(desktopWindowClosed()));
|
||||||
|
|
||||||
QObject::connect(tabletRootWindow, SIGNAL(webEventReceived(QVariant)), this, SLOT(emitWebEvent(QVariant)), Qt::DirectConnection);
|
QObject::connect(tabletRootWindow, SIGNAL(webEventReceived(QVariant)), this, SLOT(emitWebEvent(QVariant)), Qt::DirectConnection);
|
||||||
|
|
||||||
// forward qml surface events to interface js
|
// forward qml surface events to interface js
|
||||||
connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml);
|
connect(tabletRootWindow, &QmlWindowClass::fromQml, this, &TabletProxy::fromQml);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
_state = State::Home;
|
_state = State::Home;
|
||||||
removeButtonsFromToolbar();
|
removeButtonsFromToolbar();
|
||||||
|
|
Loading…
Reference in a new issue