diff --git a/examples/edit.js b/examples/edit.js
index 12072cf41f..4c953c2211 100644
--- a/examples/edit.js
+++ b/examples/edit.js
@@ -137,6 +137,7 @@ var toolBar = (function () {
newSphereButton,
newLightButton,
newTextButton,
+ newWebButton,
newZoneButton,
browseMarketplaceButton;
@@ -204,6 +205,16 @@ var toolBar = (function () {
alpha: 0.9,
visible: false
});
+
+ newWebButton = toolBar.addTool({
+ imageURL: toolIconUrl + "add-text.svg",
+ subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
+ width: toolWidth,
+ height: toolHeight,
+ alpha: 0.9,
+ visible: false
+ });
+
newZoneButton = toolBar.addTool({
imageURL: toolIconUrl + "zonecube_text.svg",
subImage: { x: 0, y: 128, width: 128, height: 128 },
@@ -253,6 +264,7 @@ var toolBar = (function () {
toolBar.showTool(newSphereButton, doShow);
toolBar.showTool(newLightButton, doShow);
toolBar.showTool(newTextButton, doShow);
+ toolBar.showTool(newWebButton, doShow);
toolBar.showTool(newZoneButton, doShow);
};
@@ -425,6 +437,23 @@ var toolBar = (function () {
return true;
}
+ if (newWebButton === toolBar.clicked(clickedOverlay)) {
+ print("Web");
+ var position = getPositionToCreateEntity();
+
+ if (position.x > 0 && position.y > 0 && position.z > 0) {
+ placingEntityID = Entities.addEntity({
+ type: "Web",
+ position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS),
+ dimensions: { x: 0.65, y: 0.3, z: 0.01 },
+ source: "http://www.slashdot.org",
+ });
+ } else {
+ print("Can't create box: Text would be out of bounds.");
+ }
+ return true;
+ }
+
if (newZoneButton === toolBar.clicked(clickedOverlay)) {
var position = getPositionToCreateEntity();
diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index 93ff80ce33..76620c9da2 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -468,6 +468,20 @@
elModelAnimationSettings.value = properties.animationSettings;
elModelTextures.value = properties.textures;
elModelOriginalTextures.value = properties.originalTextures;
+ } else if (properties.type == "Web") {
+ for (var i = 0; i < elTextSections.length; i++) {
+ elTextSections[i].style.display = 'block';
+ }
+
+ elTextText.value = properties.text;
+ elTextLineHeight.value = properties.lineHeight.toFixed(4);
+ elTextTextColor.style.backgroundColor = "rgb(" + properties.textColor.red + "," + properties.textColor.green + "," + properties.textColor.blue + ")";
+ elTextTextColorRed.value = properties.textColor.red;
+ elTextTextColorGreen.value = properties.textColor.green;
+ elTextTextColorBlue.value = properties.textColor.blue;
+ elTextBackgroundColorRed.value = properties.backgroundColor.red;
+ elTextBackgroundColorGreen.value = properties.backgroundColor.green;
+ elTextBackgroundColorBlue.value = properties.backgroundColor.blue;
} else if (properties.type == "Text") {
for (var i = 0; i < elTextSections.length; i++) {
elTextSections[i].style.display = 'block';
@@ -1019,6 +1033,12 @@
+
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index 50477356cb..b79e8ba219 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -35,6 +35,7 @@
#include "RenderableParticleEffectEntityItem.h"
#include "RenderableSphereEntityItem.h"
#include "RenderableTextEntityItem.h"
+#include "RenderableWebEntityItem.h"
#include "RenderableZoneEntityItem.h"
#include "EntitiesRendererLogging.h"
@@ -57,6 +58,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, RenderableSphereEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Text, RenderableTextEntityItem::factory)
+ REGISTER_ENTITY_TYPE_WITH_FACTORY(Web, RenderableWebEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
new file mode 100644
index 0000000000..564c49e7bd
--- /dev/null
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp
@@ -0,0 +1,59 @@
+//
+// Created by Bradley Austin Davis on 2015/05/12
+// Copyright 2013 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 "RenderableWebEntityItem.h"
+
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include "GLMHelpers.h"
+
+const int FIXED_FONT_POINT_SIZE = 40;
+
+EntityItem* RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
+ return new RenderableWebEntityItem(entityID, properties);
+}
+
+void RenderableWebEntityItem::render(RenderArgs* args) {
+ PerformanceTimer perfTimer("RenderableWebEntityItem::render");
+ assert(getType() == EntityTypes::Web);
+ glm::vec3 position = getPosition();
+ glm::vec3 dimensions = getDimensions();
+ glm::vec3 halfDimensions = dimensions / 2.0f;
+ glm::quat rotation = getRotation();
+ float leftMargin = 0.1f;
+ float topMargin = 0.1f;
+
+ //qCDebug(entitytree) << "RenderableWebEntityItem::render() id:" << getEntityItemID() << "text:" << getText();
+
+ glPushMatrix();
+ {
+ glTranslatef(position.x, position.y, position.z);
+ glm::vec3 axis = glm::axis(rotation);
+ glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
+
+ float alpha = 1.0f; //getBackgroundAlpha();
+
+ glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0);
+ glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0);
+
+ // TODO: Determine if we want these entities to have the deferred lighting effect? I think we do, so that the color
+ // used for a sphere, or box have the same look as those used on a text entity.
+ DependencyManager::get()->bindSimpleProgram();
+ DependencyManager::get()->renderQuad(topLeft, bottomRight, glm::vec4(0, 1, 0, alpha));
+ DependencyManager::get()->releaseSimpleProgram();
+ }
+ glPopMatrix();
+}
+
diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h
new file mode 100644
index 0000000000..2d639b85a1
--- /dev/null
+++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h
@@ -0,0 +1,26 @@
+//
+// Created by Bradley Austin Davis on 2015/05/12
+// Copyright 2013 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_RenderableWebEntityItem_h
+#define hifi_RenderableWebEntityItem_h
+
+#include
+
+class RenderableWebEntityItem : public WebEntityItem {
+public:
+ static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
+
+ RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
+ WebEntityItem(entityItemID, properties)
+ { }
+
+ virtual void render(RenderArgs* args);
+};
+
+
+#endif // hifi_RenderableWebEntityItem_h
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index 0accdf0899..ebdbfb4765 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -52,6 +52,7 @@ class EntityItemProperties {
friend class TextEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class ParticleEffectEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods
+ friend class WebEntityItem; // TODO....
public:
EntityItemProperties();
virtual ~EntityItemProperties();
diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index 93b8c76216..cf7fc671a0 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -148,6 +148,10 @@ enum EntityPropertyList {
PROP_SKYBOX_URL = PROP_ANIMATION_FPS,
PROP_STAGE_AUTOMATIC_HOURDAY = PROP_ANIMATION_FRAME_INDEX,
+ // Aliases/Piggyback properties for Web. These properties intentionally reuse the enum values for
+ // other properties which will never overlap with each other.
+ PROP_SOURCE_URL = PROP_MODEL_URL,
+
// WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above
};
diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp
index f0baa3da93..a9f741e581 100644
--- a/libraries/entities/src/EntityTypes.cpp
+++ b/libraries/entities/src/EntityTypes.cpp
@@ -24,6 +24,7 @@
#include "ParticleEffectEntityItem.h"
#include "SphereEntityItem.h"
#include "TextEntityItem.h"
+#include "WebEntityItem.h"
#include "ZoneEntityItem.h"
QMap EntityTypes::_typeToNameMap;
@@ -36,6 +37,7 @@ const QString ENTITY_TYPE_NAME_UNKNOWN = "Unknown";
// Register Entity the default implementations of entity types here...
REGISTER_ENTITY_TYPE(Model)
REGISTER_ENTITY_TYPE(Box)
+REGISTER_ENTITY_TYPE(Web)
REGISTER_ENTITY_TYPE(Sphere)
REGISTER_ENTITY_TYPE(Light)
REGISTER_ENTITY_TYPE(Text)
diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h
index 28cfe2278b..02038829f6 100644
--- a/libraries/entities/src/EntityTypes.h
+++ b/libraries/entities/src/EntityTypes.h
@@ -30,13 +30,14 @@ class EntityTypes {
public:
typedef enum EntityType_t {
Unknown,
- Model,
Box,
- Sphere,
Light,
+ Model,
+ ParticleEffect,
+ Sphere,
Text,
- ParticleEffect,
- Zone,
+ Web,
+ Zone,
LAST = Zone
} EntityType;
diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp
new file mode 100644
index 0000000000..3771a8831d
--- /dev/null
+++ b/libraries/entities/src/WebEntityItem.cpp
@@ -0,0 +1,145 @@
+//
+// Created by Bradley Austin Davis on 2015/05/12
+// Copyright 2013 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 "WebEntityItem.h"
+
+#include
+
+#include
+
+#include
+#include
+
+#include "EntityTree.h"
+#include "EntityTreeElement.h"
+#include "EntitiesLogging.h"
+
+
+const QString WebEntityItem::DEFAULT_SOURCE_URL("http://www.google.com");
+
+EntityItem* WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
+ EntityItem* result = new WebEntityItem(entityID, properties);
+ return result;
+}
+
+WebEntityItem::WebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
+ EntityItem(entityItemID)
+{
+ _type = EntityTypes::Web;
+ _created = properties.getCreated();
+ setProperties(properties);
+}
+
+const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f;
+
+void WebEntityItem::setDimensions(const glm::vec3& value) {
+ // NOTE: Web Entities always have a "depth" of 1cm.
+ _dimensions = glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH);
+}
+
+EntityItemProperties WebEntityItem::getProperties() const {
+ EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getSource);
+ return properties;
+}
+
+bool WebEntityItem::setProperties(const EntityItemProperties& properties) {
+ bool somethingChanged = false;
+ somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
+
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setSource);
+
+ if (somethingChanged) {
+ bool wantDebug = false;
+ if (wantDebug) {
+ uint64_t now = usecTimestampNow();
+ int elapsed = now - getLastEdited();
+ qCDebug(entities) << "WebEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
+ "now=" << now << " getLastEdited()=" << getLastEdited();
+ }
+ setLastEdited(properties._lastEdited);
+ }
+
+ return somethingChanged;
+}
+
+int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
+ ReadBitstreamToTreeParams& args,
+ EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
+
+ int bytesRead = 0;
+ const unsigned char* dataAt = data;
+
+ READ_ENTITY_PROPERTY_STRING(PROP_SOURCE_URL, setSource);
+
+ return bytesRead;
+}
+
+
+// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
+EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
+ EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
+ requestedProperties += PROP_SOURCE_URL;
+ return requestedProperties;
+}
+
+void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
+ EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
+ EntityPropertyFlags& requestedProperties,
+ EntityPropertyFlags& propertyFlags,
+ EntityPropertyFlags& propertiesDidntFit,
+ int& propertyCount,
+ OctreeElement::AppendState& appendState) const {
+
+ bool successPropertyFits = true;
+ APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, appendValue, _source);
+}
+
+
+bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+ bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
+ void** intersectedObject, bool precisionPicking) const {
+
+ RayIntersectionInfo rayInfo;
+ rayInfo._rayStart = origin;
+ rayInfo._rayDirection = direction;
+ rayInfo._rayLength = std::numeric_limits::max();
+
+ PlaneShape plane;
+
+ const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f);
+ glm::vec3 normal = _rotation * UNROTATED_NORMAL;
+ plane.setNormal(normal);
+ plane.setPoint(getPosition()); // the position is definitely a point on our plane
+
+ bool intersects = plane.findRayIntersection(rayInfo);
+
+ if (intersects) {
+ glm::vec3 hitAt = origin + (direction * rayInfo._hitDistance);
+ // now we know the point the ray hit our plane
+
+ glm::mat4 rotation = glm::mat4_cast(getRotation());
+ glm::mat4 translation = glm::translate(getPosition());
+ glm::mat4 entityToWorldMatrix = translation * rotation;
+ glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
+
+ glm::vec3 dimensions = getDimensions();
+ glm::vec3 registrationPoint = getRegistrationPoint();
+ glm::vec3 corner = -(dimensions * registrationPoint);
+ AABox entityFrameBox(corner, dimensions);
+
+ glm::vec3 entityFrameHitAt = glm::vec3(worldToEntityMatrix * glm::vec4(hitAt, 1.0f));
+
+ intersects = entityFrameBox.contains(entityFrameHitAt);
+ }
+
+ if (intersects) {
+ distance = rayInfo._hitDistance;
+ }
+ return intersects;
+}
diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h
new file mode 100644
index 0000000000..35b1c79dc1
--- /dev/null
+++ b/libraries/entities/src/WebEntityItem.h
@@ -0,0 +1,59 @@
+//
+// Created by Bradley Austin Davis on 2015/05/12
+// Copyright 2013 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_WebEntityItem_h
+#define hifi_WebEntityItem_h
+
+#include "EntityItem.h"
+
+class WebEntityItem : public EntityItem {
+public:
+ static const QString DEFAULT_SOURCE_URL;
+
+ static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
+
+ WebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
+
+ ALLOW_INSTANTIATION // This class can be instantiated
+
+ /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
+ virtual void setDimensions(const glm::vec3& value);
+ virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
+
+ // methods for getting/setting all properties of an entity
+ virtual EntityItemProperties getProperties() const;
+ virtual bool setProperties(const EntityItemProperties& properties);
+
+ // TODO: eventually only include properties changed since the params.lastViewFrustumSent time
+ virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
+
+ virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
+ EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
+ EntityPropertyFlags& requestedProperties,
+ EntityPropertyFlags& propertyFlags,
+ EntityPropertyFlags& propertiesDidntFit,
+ int& propertyCount,
+ OctreeElement::AppendState& appendState) const;
+
+ virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
+ ReadBitstreamToTreeParams& args,
+ EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
+
+ virtual bool supportsDetailedRayIntersection() const { return true; }
+ virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+ bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
+ void** intersectedObject, bool precisionPicking) const;
+
+ void setSourceUrl(const QString& value) { _sourceUrl = value; }
+ const QString& getSource() const { return _sourceUrl; }
+
+protected:
+ QString _sourceUrl;
+};
+
+#endif // hifi_WebEntityItem_h
diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp
index 7d13a00324..b133d1e488 100644
--- a/libraries/ui/src/OffscreenUi.cpp
+++ b/libraries/ui/src/OffscreenUi.cpp
@@ -24,30 +24,10 @@ Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
// achieve.
static const int SMALL_INTERVAL = 5;
-class OffscreenUiRoot : public QQuickItem {
- Q_OBJECT
-public:
-
- OffscreenUiRoot(QQuickItem* parent = 0);
- Q_INVOKABLE void information(const QString& title, const QString& text);
- Q_INVOKABLE void loadChild(const QUrl& url) {
- DependencyManager::get()->load(url);
- }
-};
-
-
-OffscreenUiRoot::OffscreenUiRoot(QQuickItem* parent) : QQuickItem(parent) {
+OffscreenQmlSurface::OffscreenQmlSurface() {
}
-void OffscreenUiRoot::information(const QString& title, const QString& text) {
- OffscreenUi::information(title, text);
-}
-
-OffscreenUi::OffscreenUi() {
- ::qmlRegisterType("Hifi", 1, 0, "Root");
-}
-
-OffscreenUi::~OffscreenUi() {
+OffscreenQmlSurface::~OffscreenQmlSurface() {
// Make sure the context is current while doing cleanup. Note that we use the
// offscreen surface here because passing 'this' at this point is not safe: the
// underlying platform window may already be destroyed. To avoid all the trouble, use
@@ -65,7 +45,7 @@ OffscreenUi::~OffscreenUi() {
doneCurrent();
}
-void OffscreenUi::create(QOpenGLContext* shareContext) {
+void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
OffscreenGlCanvas::create(shareContext);
makeCurrent();
@@ -87,13 +67,13 @@ void OffscreenUi::create(QOpenGLContext* shareContext) {
// a timer with a small interval is used to get better performance.
_updateTimer.setSingleShot(true);
_updateTimer.setInterval(SMALL_INTERVAL);
- connect(&_updateTimer, &QTimer::timeout, this, &OffscreenUi::updateQuick);
+ connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick);
// Now hook up the signals. For simplicy we don't differentiate between
// renderRequested (only render is needed, no sync) and sceneChanged (polish and sync
// is needed too).
- connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenUi::requestRender);
- connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenUi::requestUpdate);
+ connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenQmlSurface::requestRender);
+ connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenQmlSurface::requestUpdate);
#ifdef DEBUG
connect(_quickWindow, &QQuickWindow::focusObjectChanged, [this]{
@@ -110,11 +90,7 @@ void OffscreenUi::create(QOpenGLContext* shareContext) {
_renderControl->initialize(&_context);
}
-void OffscreenUi::addImportPath(const QString& path) {
- _qmlEngine->addImportPath(path);
-}
-
-void OffscreenUi::resize(const QSize& newSize) {
+void OffscreenQmlSurface::resize(const QSize& newSize) {
makeCurrent();
qreal pixelRatio = _renderControl->_renderWindow ? _renderControl->_renderWindow->devicePixelRatio() : 1.0;
@@ -141,15 +117,15 @@ void OffscreenUi::resize(const QSize& newSize) {
doneCurrent();
}
-QQuickItem* OffscreenUi::getRootItem() {
+QQuickItem* OffscreenQmlSurface::getRootItem() {
return _rootItem;
}
-void OffscreenUi::setBaseUrl(const QUrl& baseUrl) {
+void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
_qmlEngine->setBaseUrl(baseUrl);
}
-QObject* OffscreenUi::load(const QUrl& qmlSource, std::function f) {
+QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function f) {
_qmlComponent->loadUrl(qmlSource);
if (_qmlComponent->isLoading()) {
connect(_qmlComponent, &QQmlComponent::statusChanged, this,
@@ -162,20 +138,20 @@ QObject* OffscreenUi::load(const QUrl& qmlSource, std::function f) {
+QObject* OffscreenQmlSurface::finishQmlLoad(std::function f) {
disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0);
if (_qmlComponent->isError()) {
QList errorList = _qmlComponent->errors();
@@ -232,7 +208,7 @@ QObject* OffscreenUi::finishQmlLoad(std::function
}
-void OffscreenUi::updateQuick() {
+void OffscreenQmlSurface::updateQuick() {
if (_paused) {
return;
}
@@ -274,7 +250,7 @@ void OffscreenUi::updateQuick() {
emit textureUpdated(fbo->texture());
}
-QPointF OffscreenUi::mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject) {
+QPointF OffscreenQmlSurface::mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject) {
vec2 sourceSize;
if (dynamic_cast(sourceObject)) {
sourceSize = toGlm(((QWidget*)sourceObject)->size());
@@ -297,7 +273,7 @@ QPointF OffscreenUi::mapWindowToUi(const QPointF& sourcePosition, QObject* sourc
bool OffscreenUi::shouldSwallowShortcut(QEvent* event) {
Q_ASSERT(event->type() == QEvent::ShortcutOverride);
QObject* focusObject = _quickWindow->focusObject();
- if (focusObject != _quickWindow && focusObject != _rootItem) {
+ if (focusObject != _quickWindow && focusObject != getRootItem()) {
//qDebug() << "Swallowed shortcut " << static_cast(event)->key();
event->accept();
return true;
@@ -310,7 +286,7 @@ bool OffscreenUi::shouldSwallowShortcut(QEvent* event) {
// Event handling customization
//
-bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
+bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* event) {
// Only intercept events while we're in an active state
if (_paused) {
return false;
@@ -389,37 +365,65 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
return false;
}
-void OffscreenUi::lockTexture(int texture) {
+void OffscreenQmlSurface::lockTexture(int texture) {
_fboCache.lockTexture(texture);
}
-void OffscreenUi::releaseTexture(int texture) {
+void OffscreenQmlSurface::releaseTexture(int texture) {
_fboCache.releaseTexture(texture);
}
-void OffscreenUi::pause() {
+void OffscreenQmlSurface::pause() {
_paused = true;
}
-void OffscreenUi::resume() {
+void OffscreenQmlSurface::resume() {
_paused = false;
requestRender();
}
-bool OffscreenUi::isPaused() const {
+bool OffscreenQmlSurface::isPaused() const {
return _paused;
}
-void OffscreenUi::setProxyWindow(QWindow* window) {
+void OffscreenQmlSurface::setProxyWindow(QWindow* window) {
_renderControl->_renderWindow = window;
}
+
+class OffscreenUiRoot : public QQuickItem {
+ Q_OBJECT
+public:
+
+ OffscreenUiRoot(QQuickItem* parent = 0);
+ Q_INVOKABLE void information(const QString& title, const QString& text);
+ Q_INVOKABLE void loadChild(const QUrl& url) {
+ DependencyManager::get()->load(url);
+ }
+};
+
+
+OffscreenUiRoot::OffscreenUiRoot(QQuickItem* parent) : QQuickItem(parent) {
+}
+
+void OffscreenUiRoot::information(const QString& title, const QString& text) {
+ OffscreenUi::information(title, text);
+}
+
+OffscreenUi::OffscreenUi() {
+ ::qmlRegisterType("Hifi", 1, 0, "Root");
+}
+
+OffscreenUi::~OffscreenUi() {
+}
+
+
void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) {
- QQuickItem* item = _rootItem->findChild(name);
+ QQuickItem* item = getRootItem()->findChild(name);
// First load?
if (!item) {
load(url, f);
- item = _rootItem->findChild(name);
+ item = getRootItem()->findChild(name);
}
if (item) {
item->setEnabled(true);
@@ -427,11 +431,11 @@ void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) {
- QQuickItem* item = _rootItem->findChild(name);
+ QQuickItem* item = getRootItem()->findChild(name);
// First load?
if (!item) {
load(url, f);
- item = _rootItem->findChild(name);
+ item = getRootItem()->findChild(name);
}
if (item) {
item->setEnabled(!item->isEnabled());
diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h
index ce40bec943..846cd4bfd6 100644
--- a/libraries/ui/src/OffscreenUi.h
+++ b/libraries/ui/src/OffscreenUi.h
@@ -96,9 +96,9 @@ private:
offscreenUi->load(QML, f); \
}
-class OffscreenUi : public OffscreenGlCanvas, public Dependency {
+class OffscreenQmlSurface : public OffscreenGlCanvas {
Q_OBJECT
-
+protected:
class QMyQuickRenderControl : public QQuickRenderControl {
protected:
QWindow* renderWindow(QPoint* offset) Q_DECL_OVERRIDE{
@@ -113,36 +113,76 @@ class OffscreenUi : public OffscreenGlCanvas, public Dependency {
private:
QWindow* _renderWindow{ nullptr };
- friend class OffscreenUi;
+ friend class OffscreenQmlSurface;
};
-
public:
+ OffscreenQmlSurface();
+ virtual ~OffscreenQmlSurface();
+
using MouseTranslator = std::function;
- OffscreenUi();
- virtual ~OffscreenUi();
+
void create(QOpenGLContext* context);
void resize(const QSize& size);
QObject* load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {});
QObject* load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) {
return load(QUrl(qmlSourceFile), f);
}
- void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {});
- void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {});
- void setBaseUrl(const QUrl& baseUrl);
- void addImportPath(const QString& path);
- //QQmlContext* getQmlContext();
- QQuickItem* getRootItem();
- void pause();
- void resume();
- bool isPaused() const;
+
+ // Optional values for event handling
void setProxyWindow(QWindow* window);
- bool shouldSwallowShortcut(QEvent* event);
- QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
- virtual bool eventFilter(QObject* originalDestination, QEvent* event);
void setMouseTranslator(MouseTranslator mouseTranslator) {
_mouseTranslator = mouseTranslator;
}
+ void pause();
+ void resume();
+ bool isPaused() const;
+
+ void setBaseUrl(const QUrl& baseUrl);
+ QQuickItem* getRootItem();
+
+ virtual bool eventFilter(QObject* originalDestination, QEvent* event);
+
+signals:
+ void textureUpdated(GLuint texture);
+
+public slots:
+ void requestUpdate();
+ void requestRender();
+ void lockTexture(int texture);
+ void releaseTexture(int texture);
+
+private:
+ QObject* finishQmlLoad(std::function f);
+ QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
+
+private slots:
+ void updateQuick();
+
+protected:
+ QQuickWindow* _quickWindow{ nullptr };
+
+private:
+ QMyQuickRenderControl* _renderControl{ new QMyQuickRenderControl };
+ QQmlEngine* _qmlEngine{ nullptr };
+ QQmlComponent* _qmlComponent{ nullptr };
+ QQuickItem* _rootItem{ nullptr };
+ QTimer _updateTimer;
+ FboCache _fboCache;
+ bool _polish{ true };
+ bool _paused{ true };
+ MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p; } };
+};
+
+class OffscreenUi : public OffscreenQmlSurface, public Dependency {
+ Q_OBJECT
+
+public:
+ OffscreenUi();
+ virtual ~OffscreenUi();
+ void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {});
+ void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {});
+ bool shouldSwallowShortcut(QEvent* event);
// Messagebox replacement functions
using ButtonCallback = std::function;
@@ -168,33 +208,6 @@ public:
static void critical(const QString& title, const QString& text,
ButtonCallback callback = NO_OP_CALLBACK,
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
-
-private:
- QObject* finishQmlLoad(std::function f);
-
-private slots:
- void updateQuick();
-
-public slots:
- void requestUpdate();
- void requestRender();
- void lockTexture(int texture);
- void releaseTexture(int texture);
-
-signals:
- void textureUpdated(GLuint texture);
-
-private:
- QMyQuickRenderControl* _renderControl{ new QMyQuickRenderControl };
- QQuickWindow* _quickWindow{ nullptr };
- QQmlEngine* _qmlEngine{ nullptr };
- QQmlComponent* _qmlComponent{ nullptr };
- QQuickItem* _rootItem{ nullptr };
- QTimer _updateTimer;
- FboCache _fboCache;
- bool _polish{ true };
- bool _paused{ true };
- MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p; } };
};
#endif