mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #11016 from highfidelity/context-overlays
Context Overlays
This commit is contained in:
commit
71ce5a6494
32 changed files with 747 additions and 332 deletions
|
@ -15,7 +15,7 @@
|
||||||
{ "comment" : "Mouse turn need to be small continuous increments",
|
{ "comment" : "Mouse turn need to be small continuous increments",
|
||||||
"from": { "makeAxis" : [
|
"from": { "makeAxis" : [
|
||||||
[ "Keyboard.MouseMoveLeft" ],
|
[ "Keyboard.MouseMoveLeft" ],
|
||||||
[ "Keyboard.MouseMoveRight" ]
|
[ "Keyboard.MouseMoveRight" ]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"when": [ "Application.InHMD", "Application.SnapTurn", "Keyboard.RightMouseButton" ],
|
"when": [ "Application.InHMD", "Application.SnapTurn", "Keyboard.RightMouseButton" ],
|
||||||
|
@ -31,8 +31,8 @@
|
||||||
{ "comment" : "Touchpad turn need to be small continuous increments, but without the RMB constraint",
|
{ "comment" : "Touchpad turn need to be small continuous increments, but without the RMB constraint",
|
||||||
"from": { "makeAxis" : [
|
"from": { "makeAxis" : [
|
||||||
[ "Keyboard.TouchpadLeft" ],
|
[ "Keyboard.TouchpadLeft" ],
|
||||||
[ "Keyboard.TouchpadRight" ]
|
[ "Keyboard.TouchpadRight" ]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"when": [ "Application.InHMD", "Application.SnapTurn" ],
|
"when": [ "Application.InHMD", "Application.SnapTurn" ],
|
||||||
"to": "Actions.StepYaw",
|
"to": "Actions.StepYaw",
|
||||||
|
|
BIN
interface/resources/images/inspect-icon.png
Normal file
BIN
interface/resources/images/inspect-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
|
@ -70,7 +70,7 @@
|
||||||
#include <EntityScriptClient.h>
|
#include <EntityScriptClient.h>
|
||||||
#include <EntityScriptServerLogClient.h>
|
#include <EntityScriptServerLogClient.h>
|
||||||
#include <EntityScriptingInterface.h>
|
#include <EntityScriptingInterface.h>
|
||||||
#include <HoverOverlayInterface.h>
|
#include "ui/overlays/ContextOverlayInterface.h"
|
||||||
#include <ErrorDialog.h>
|
#include <ErrorDialog.h>
|
||||||
#include <FileScriptingInterface.h>
|
#include <FileScriptingInterface.h>
|
||||||
#include <Finally.h>
|
#include <Finally.h>
|
||||||
|
@ -595,7 +595,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
DependencyManager::set<Snapshot>();
|
DependencyManager::set<Snapshot>();
|
||||||
DependencyManager::set<CloseEventSender>();
|
DependencyManager::set<CloseEventSender>();
|
||||||
DependencyManager::set<ResourceManager>();
|
DependencyManager::set<ResourceManager>();
|
||||||
DependencyManager::set<HoverOverlayInterface>();
|
DependencyManager::set<ContextOverlayInterface>();
|
||||||
|
|
||||||
return previousSessionCrashed;
|
return previousSessionCrashed;
|
||||||
}
|
}
|
||||||
|
@ -1324,12 +1324,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
// Keyboard focus handling for Web overlays.
|
// Keyboard focus handling for Web overlays.
|
||||||
auto overlays = &(qApp->getOverlays());
|
auto overlays = &(qApp->getOverlays());
|
||||||
|
|
||||||
connect(overlays, &Overlays::mousePressOnOverlay, [=](OverlayID overlayID, const PointerEvent& event) {
|
connect(overlays, &Overlays::mousePressOnOverlay, [=](const OverlayID& overlayID, const PointerEvent& event) {
|
||||||
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlays->getOverlay(overlayID));
|
||||||
setKeyboardFocusOverlay(overlayID);
|
// Only Web overlays can have keyboard focus.
|
||||||
|
if (thisOverlay) {
|
||||||
|
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
||||||
|
setKeyboardFocusOverlay(overlayID);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(overlays, &Overlays::overlayDeleted, [=](OverlayID overlayID) {
|
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {
|
||||||
if (overlayID == _keyboardFocusedOverlay.get()) {
|
if (overlayID == _keyboardFocusedOverlay.get()) {
|
||||||
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
|
setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
|
||||||
}
|
}
|
||||||
|
@ -1344,6 +1348,21 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(overlays,
|
||||||
|
SIGNAL(mousePressOnOverlay(const OverlayID&, const PointerEvent&)),
|
||||||
|
DependencyManager::get<ContextOverlayInterface>().data(),
|
||||||
|
SLOT(contextOverlays_mousePressOnOverlay(const OverlayID&, const PointerEvent&)));
|
||||||
|
|
||||||
|
connect(overlays,
|
||||||
|
SIGNAL(hoverEnterOverlay(const OverlayID&, const PointerEvent&)),
|
||||||
|
DependencyManager::get<ContextOverlayInterface>().data(),
|
||||||
|
SLOT(contextOverlays_hoverEnterOverlay(const OverlayID&, const PointerEvent&)));
|
||||||
|
|
||||||
|
connect(overlays,
|
||||||
|
SIGNAL(hoverLeaveOverlay(const OverlayID&, const PointerEvent&)),
|
||||||
|
DependencyManager::get<ContextOverlayInterface>().data(),
|
||||||
|
SLOT(contextOverlays_hoverLeaveOverlay(const OverlayID&, const PointerEvent&)));
|
||||||
|
|
||||||
// Add periodic checks to send user activity data
|
// Add periodic checks to send user activity data
|
||||||
static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000;
|
static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000;
|
||||||
static int NEARBY_AVATAR_RADIUS_METERS = 10;
|
static int NEARBY_AVATAR_RADIUS_METERS = 10;
|
||||||
|
@ -1470,7 +1489,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
properties["atp_mapping_requests"] = atpMappingRequests;
|
properties["atp_mapping_requests"] = atpMappingRequests;
|
||||||
|
|
||||||
properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
|
properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
|
||||||
|
|
||||||
QJsonObject bytesDownloaded;
|
QJsonObject bytesDownloaded;
|
||||||
bytesDownloaded["atp"] = statTracker->getStat(STAT_ATP_RESOURCE_TOTAL_BYTES).toInt();
|
bytesDownloaded["atp"] = statTracker->getStat(STAT_ATP_RESOURCE_TOTAL_BYTES).toInt();
|
||||||
bytesDownloaded["http"] = statTracker->getStat(STAT_HTTP_RESOURCE_TOTAL_BYTES).toInt();
|
bytesDownloaded["http"] = statTracker->getStat(STAT_HTTP_RESOURCE_TOTAL_BYTES).toInt();
|
||||||
|
@ -2131,7 +2150,7 @@ void Application::initializeUi() {
|
||||||
surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
|
surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
|
||||||
|
|
||||||
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
|
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
|
||||||
surfaceContext->setContextProperty("HoverOverlay", DependencyManager::get<HoverOverlayInterface>().data());
|
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
|
||||||
|
|
||||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||||
surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
|
surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get()));
|
||||||
|
@ -5397,6 +5416,17 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
}
|
}
|
||||||
renderArgs->_debugFlags = renderDebugFlags;
|
renderArgs->_debugFlags = renderDebugFlags;
|
||||||
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, transaction);
|
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, transaction);
|
||||||
|
|
||||||
|
RenderArgs::OutlineFlags renderOutlineFlags = RenderArgs::RENDER_OUTLINE_NONE;
|
||||||
|
auto contextOverlayInterface = DependencyManager::get<ContextOverlayInterface>();
|
||||||
|
if (contextOverlayInterface->getEnabled()) {
|
||||||
|
if (DependencyManager::get<ContextOverlayInterface>()->getIsInMarketplaceInspectionMode()) {
|
||||||
|
renderOutlineFlags = RenderArgs::RENDER_OUTLINE_MARKETPLACE_MODE;
|
||||||
|
} else {
|
||||||
|
renderOutlineFlags = RenderArgs::RENDER_OUTLINE_WIREFRAMES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderArgs->_outlineFlags = renderOutlineFlags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5860,7 +5890,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
||||||
auto entityScriptServerLog = DependencyManager::get<EntityScriptServerLogClient>();
|
auto entityScriptServerLog = DependencyManager::get<EntityScriptServerLogClient>();
|
||||||
scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data());
|
scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data());
|
||||||
scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance());
|
scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance());
|
||||||
scriptEngine->registerGlobalObject("HoverOverlay", DependencyManager::get<HoverOverlayInterface>().data());
|
scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
|
||||||
|
|
||||||
qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue);
|
qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue);
|
||||||
|
|
||||||
|
|
271
interface/src/ui/overlays/ContextOverlayInterface.cpp
Normal file
271
interface/src/ui/overlays/ContextOverlayInterface.cpp
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
//
|
||||||
|
// ContextOverlayInterface.cpp
|
||||||
|
// interface/src/ui/overlays
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2017-07-14.
|
||||||
|
// Copyright 2017 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 "ContextOverlayInterface.h"
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
#include <EntityTreeRenderer.h>
|
||||||
|
|
||||||
|
static const float CONTEXT_OVERLAY_TABLET_OFFSET = 30.0f; // Degrees
|
||||||
|
static const float CONTEXT_OVERLAY_TABLET_ORIENTATION = 210.0f; // Degrees
|
||||||
|
static const float CONTEXT_OVERLAY_TABLET_DISTANCE = 0.65F; // Meters
|
||||||
|
ContextOverlayInterface::ContextOverlayInterface() {
|
||||||
|
// "context_overlay" debug log category disabled by default.
|
||||||
|
// Create your own "qtlogging.ini" file and set your "QT_LOGGING_CONF" environment variable
|
||||||
|
// if you'd like to enable/disable certain categories.
|
||||||
|
// More details: http://doc.qt.io/qt-5/qloggingcategory.html#configuring-categories
|
||||||
|
QLoggingCategory::setFilterRules(QStringLiteral("hifi.context_overlay.debug=false"));
|
||||||
|
|
||||||
|
_entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||||
|
_hmdScriptingInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
_tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
|
||||||
|
_entityPropertyFlags += PROP_POSITION;
|
||||||
|
_entityPropertyFlags += PROP_ROTATION;
|
||||||
|
_entityPropertyFlags += PROP_MARKETPLACE_ID;
|
||||||
|
_entityPropertyFlags += PROP_DIMENSIONS;
|
||||||
|
_entityPropertyFlags += PROP_REGISTRATION_POINT;
|
||||||
|
|
||||||
|
// initially, set _enabled to match the switch. Later we enable/disable via the getter/setters
|
||||||
|
// if we are in edit or pal (for instance). Note this is temporary, as we expect to enable this all
|
||||||
|
// the time after getting edge highlighting, etc...
|
||||||
|
_enabled = _settingSwitch.get();
|
||||||
|
|
||||||
|
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>().data();
|
||||||
|
connect(entityTreeRenderer, SIGNAL(mousePressOnEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(createOrDestroyContextOverlay(const EntityItemID&, const PointerEvent&)));
|
||||||
|
connect(entityTreeRenderer, SIGNAL(hoverEnterEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverEnterEntity(const EntityItemID&, const PointerEvent&)));
|
||||||
|
connect(entityTreeRenderer, SIGNAL(hoverLeaveEntity(const EntityItemID&, const PointerEvent&)), this, SLOT(contextOverlays_hoverLeaveEntity(const EntityItemID&, const PointerEvent&)));
|
||||||
|
connect(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"), &TabletProxy::tabletShownChanged, this, [&]() {
|
||||||
|
if (_contextOverlayJustClicked && _hmdScriptingInterface->isMounted()) {
|
||||||
|
QUuid tabletFrameID = _hmdScriptingInterface->getCurrentTabletFrameID();
|
||||||
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
|
glm::quat cameraOrientation = qApp->getCamera().getOrientation();
|
||||||
|
QVariantMap props;
|
||||||
|
props.insert("position", vec3toVariant(myAvatar->getEyePosition() + glm::quat(glm::radians(glm::vec3(0.0f, CONTEXT_OVERLAY_TABLET_OFFSET, 0.0f))) * (CONTEXT_OVERLAY_TABLET_DISTANCE * (cameraOrientation * Vectors::FRONT))));
|
||||||
|
props.insert("orientation", quatToVariant(cameraOrientation * glm::quat(glm::radians(glm::vec3(0.0f, CONTEXT_OVERLAY_TABLET_ORIENTATION, 0.0f)))));
|
||||||
|
qApp->getOverlays().editOverlay(tabletFrameID, props);
|
||||||
|
_contextOverlayJustClicked = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint32_t LEFT_HAND_HW_ID = 1;
|
||||||
|
static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 };
|
||||||
|
static const float CONTEXT_OVERLAY_INSIDE_DISTANCE = 1.0f; // in meters
|
||||||
|
static const float CONTEXT_OVERLAY_CLOSE_DISTANCE = 1.5f; // in meters
|
||||||
|
static const float CONTEXT_OVERLAY_CLOSE_SIZE = 0.12f; // in meters, same x and y dims
|
||||||
|
static const float CONTEXT_OVERLAY_FAR_SIZE = 0.08f; // in meters, same x and y dims
|
||||||
|
static const float CONTEXT_OVERLAY_CLOSE_OFFSET_ANGLE = 20.0f;
|
||||||
|
static const float CONTEXT_OVERLAY_UNHOVERED_ALPHA = 0.85f;
|
||||||
|
static const float CONTEXT_OVERLAY_HOVERED_ALPHA = 1.0f;
|
||||||
|
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMIN = 0.6f;
|
||||||
|
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEMAX = 1.0f;
|
||||||
|
static const float CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD = 1.0f;
|
||||||
|
static const float CONTEXT_OVERLAY_UNHOVERED_COLORPULSE = 1.0f;
|
||||||
|
static const float CONTEXT_OVERLAY_FAR_OFFSET = 0.1f;
|
||||||
|
|
||||||
|
void ContextOverlayInterface::setEnabled(bool enabled) {
|
||||||
|
// only enable/disable if the setting in 'on'. If it is 'off',
|
||||||
|
// make sure _enabled is always false.
|
||||||
|
if (_settingSwitch.get()) {
|
||||||
|
_enabled = enabled;
|
||||||
|
} else {
|
||||||
|
_enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||||
|
if (_enabled && event.getButton() == PointerEvent::SecondaryButton) {
|
||||||
|
if (contextOverlayFilterPassed(entityItemID)) {
|
||||||
|
qCDebug(context_overlay) << "Creating Context Overlay on top of entity with ID: " << entityItemID;
|
||||||
|
|
||||||
|
// Add all necessary variables to the stack
|
||||||
|
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags);
|
||||||
|
glm::vec3 cameraPosition = qApp->getCamera().getPosition();
|
||||||
|
float distanceFromCameraToEntity = glm::distance(entityProperties.getPosition(), cameraPosition);
|
||||||
|
glm::vec3 entityDimensions = entityProperties.getDimensions();
|
||||||
|
glm::vec3 entityPosition = entityProperties.getPosition();
|
||||||
|
glm::vec3 contextOverlayPosition = entityProperties.getPosition();
|
||||||
|
glm::vec2 contextOverlayDimensions;
|
||||||
|
|
||||||
|
// Update the position of the overlay if the registration point of the entity
|
||||||
|
// isn't default
|
||||||
|
if (entityProperties.getRegistrationPoint() != glm::vec3(0.5f)) {
|
||||||
|
glm::vec3 adjustPos = entityProperties.getRegistrationPoint() - glm::vec3(0.5f);
|
||||||
|
entityPosition = entityPosition - (entityProperties.getRotation() * (adjustPos * entityProperties.getDimensions()));
|
||||||
|
}
|
||||||
|
|
||||||
|
enableEntityHighlight(entityItemID);
|
||||||
|
|
||||||
|
AABox boundingBox = AABox(entityPosition - (entityDimensions / 2.0f), entityDimensions * 2.0f);
|
||||||
|
|
||||||
|
// Update the cached Entity Marketplace ID
|
||||||
|
_entityMarketplaceID = entityProperties.getMarketplaceID();
|
||||||
|
|
||||||
|
|
||||||
|
if (!_currentEntityWithContextOverlay.isNull() && _currentEntityWithContextOverlay != entityItemID) {
|
||||||
|
disableEntityHighlight(_currentEntityWithContextOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the cached "Current Entity with Context Overlay" variable
|
||||||
|
setCurrentEntityWithContextOverlay(entityItemID);
|
||||||
|
|
||||||
|
// Here, we determine the position and dimensions of the Context Overlay.
|
||||||
|
if (boundingBox.contains(cameraPosition)) {
|
||||||
|
// If the camera is inside the box...
|
||||||
|
// ...position the Context Overlay 1 meter in front of the camera.
|
||||||
|
contextOverlayPosition = cameraPosition + CONTEXT_OVERLAY_INSIDE_DISTANCE * (qApp->getCamera().getOrientation() * Vectors::FRONT);
|
||||||
|
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_CLOSE_SIZE, CONTEXT_OVERLAY_CLOSE_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
||||||
|
} else if (distanceFromCameraToEntity < CONTEXT_OVERLAY_CLOSE_DISTANCE) {
|
||||||
|
// Else if the entity is too close to the camera...
|
||||||
|
// ...rotate the Context Overlay to the right of the entity.
|
||||||
|
// This makes it easy to inspect things you're holding.
|
||||||
|
float offsetAngle = -CONTEXT_OVERLAY_CLOSE_OFFSET_ANGLE;
|
||||||
|
if (event.getID() == LEFT_HAND_HW_ID) {
|
||||||
|
offsetAngle *= -1;
|
||||||
|
}
|
||||||
|
contextOverlayPosition = (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f))) * (entityPosition - cameraPosition)) + cameraPosition;
|
||||||
|
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_CLOSE_SIZE, CONTEXT_OVERLAY_CLOSE_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
||||||
|
} else {
|
||||||
|
// Else, place the Context Overlay some offset away from the entity's bounding
|
||||||
|
// box in the direction of the camera.
|
||||||
|
glm::vec3 direction = glm::normalize(entityPosition - cameraPosition);
|
||||||
|
float distance;
|
||||||
|
BoxFace face;
|
||||||
|
glm::vec3 normal;
|
||||||
|
boundingBox.findRayIntersection(cameraPosition, direction, distance, face, normal);
|
||||||
|
contextOverlayPosition = (cameraPosition + direction * distance) - direction * CONTEXT_OVERLAY_FAR_OFFSET;
|
||||||
|
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_FAR_SIZE, CONTEXT_OVERLAY_FAR_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, setup and draw the Context Overlay
|
||||||
|
if (_contextOverlayID == UNKNOWN_OVERLAY_ID || !qApp->getOverlays().isAddedOverlay(_contextOverlayID)) {
|
||||||
|
_contextOverlay = std::make_shared<Image3DOverlay>();
|
||||||
|
_contextOverlay->setAlpha(CONTEXT_OVERLAY_UNHOVERED_ALPHA);
|
||||||
|
_contextOverlay->setPulseMin(CONTEXT_OVERLAY_UNHOVERED_PULSEMIN);
|
||||||
|
_contextOverlay->setPulseMax(CONTEXT_OVERLAY_UNHOVERED_PULSEMAX);
|
||||||
|
_contextOverlay->setColorPulse(CONTEXT_OVERLAY_UNHOVERED_COLORPULSE);
|
||||||
|
_contextOverlay->setIgnoreRayIntersection(false);
|
||||||
|
_contextOverlay->setDrawInFront(true);
|
||||||
|
_contextOverlay->setURL(PathUtils::resourcesPath() + "images/inspect-icon.png");
|
||||||
|
_contextOverlay->setIsFacingAvatar(true);
|
||||||
|
_contextOverlayID = qApp->getOverlays().addOverlay(_contextOverlay);
|
||||||
|
}
|
||||||
|
_contextOverlay->setPosition(contextOverlayPosition);
|
||||||
|
_contextOverlay->setDimensions(contextOverlayDimensions);
|
||||||
|
_contextOverlay->setRotation(entityProperties.getRotation());
|
||||||
|
_contextOverlay->setVisible(true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!_currentEntityWithContextOverlay.isNull()) {
|
||||||
|
return destroyContextOverlay(_currentEntityWithContextOverlay, event);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContextOverlayInterface::contextOverlayFilterPassed(const EntityItemID& entityItemID) {
|
||||||
|
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags);
|
||||||
|
return (entityProperties.getMarketplaceID().length() != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||||
|
if (_contextOverlayID != UNKNOWN_OVERLAY_ID) {
|
||||||
|
qCDebug(context_overlay) << "Destroying Context Overlay on top of entity with ID: " << entityItemID;
|
||||||
|
disableEntityHighlight(entityItemID);
|
||||||
|
setCurrentEntityWithContextOverlay(QUuid());
|
||||||
|
_entityMarketplaceID.clear();
|
||||||
|
// Destroy the Context Overlay
|
||||||
|
qApp->getOverlays().deleteOverlay(_contextOverlayID);
|
||||||
|
_contextOverlay = NULL;
|
||||||
|
_contextOverlayID = UNKNOWN_OVERLAY_ID;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityItemID) {
|
||||||
|
return ContextOverlayInterface::destroyContextOverlay(entityItemID, PointerEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextOverlayInterface::contextOverlays_mousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||||
|
if (overlayID == _contextOverlayID && event.getButton() == PointerEvent::PrimaryButton) {
|
||||||
|
qCDebug(context_overlay) << "Clicked Context Overlay. Entity ID:" << _currentEntityWithContextOverlay << "Overlay ID:" << overlayID;
|
||||||
|
openMarketplace();
|
||||||
|
destroyContextOverlay(_currentEntityWithContextOverlay, PointerEvent());
|
||||||
|
_contextOverlayJustClicked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextOverlayInterface::contextOverlays_hoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||||
|
if (_contextOverlayID != UNKNOWN_OVERLAY_ID && _contextOverlay) {
|
||||||
|
qCDebug(context_overlay) << "Started hovering over Context Overlay. Overlay ID:" << overlayID;
|
||||||
|
_contextOverlay->setColor(CONTEXT_OVERLAY_COLOR);
|
||||||
|
_contextOverlay->setColorPulse(0.0f); // pulse off
|
||||||
|
_contextOverlay->setPulsePeriod(0.0f); // pulse off
|
||||||
|
_contextOverlay->setAlpha(CONTEXT_OVERLAY_HOVERED_ALPHA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||||
|
if (_contextOverlayID != UNKNOWN_OVERLAY_ID && _contextOverlay) {
|
||||||
|
qCDebug(context_overlay) << "Stopped hovering over Context Overlay. Overlay ID:" << overlayID;
|
||||||
|
_contextOverlay->setColor(CONTEXT_OVERLAY_COLOR);
|
||||||
|
_contextOverlay->setColorPulse(CONTEXT_OVERLAY_UNHOVERED_COLORPULSE);
|
||||||
|
_contextOverlay->setPulsePeriod(CONTEXT_OVERLAY_UNHOVERED_PULSEPERIOD);
|
||||||
|
_contextOverlay->setAlpha(CONTEXT_OVERLAY_UNHOVERED_ALPHA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event) {
|
||||||
|
if (contextOverlayFilterPassed(entityID)) {
|
||||||
|
enableEntityHighlight(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event) {
|
||||||
|
if (_currentEntityWithContextOverlay != entityID) {
|
||||||
|
disableEntityHighlight(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const QString MARKETPLACE_BASE_URL = "https://metaverse.highfidelity.com/marketplace/items/";
|
||||||
|
|
||||||
|
void ContextOverlayInterface::openMarketplace() {
|
||||||
|
// lets open the tablet and go to the current item in
|
||||||
|
// the marketplace (if the current entity has a
|
||||||
|
// marketplaceID)
|
||||||
|
if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
|
||||||
|
auto tablet = dynamic_cast<TabletProxy*>(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
|
||||||
|
// construct the url to the marketplace item
|
||||||
|
QString url = MARKETPLACE_BASE_URL + _entityMarketplaceID;
|
||||||
|
tablet->gotoWebScreen(url);
|
||||||
|
_hmdScriptingInterface->openTablet();
|
||||||
|
_isInMarketplaceInspectionMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) {
|
||||||
|
if (!qApp->getEntities()->getTree()->findEntityByEntityItemID(entityItemID)->getShouldHighlight()) {
|
||||||
|
qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'true' for Entity ID:" << entityItemID;
|
||||||
|
qApp->getEntities()->getTree()->findEntityByEntityItemID(entityItemID)->setShouldHighlight(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContextOverlayInterface::disableEntityHighlight(const EntityItemID& entityItemID) {
|
||||||
|
if (qApp->getEntities()->getTree()->findEntityByEntityItemID(entityItemID)->getShouldHighlight()) {
|
||||||
|
qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'false' for Entity ID:" << entityItemID;
|
||||||
|
qApp->getEntities()->getTree()->findEntityByEntityItemID(entityItemID)->setShouldHighlight(false);
|
||||||
|
}
|
||||||
|
}
|
85
interface/src/ui/overlays/ContextOverlayInterface.h
Normal file
85
interface/src/ui/overlays/ContextOverlayInterface.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
//
|
||||||
|
// ContextOverlayInterface.h
|
||||||
|
// interface/src/ui/overlays
|
||||||
|
//
|
||||||
|
// Created by Zach Fox on 2017-07-14.
|
||||||
|
// Copyright 2017 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_ContextOverlayInterface_h
|
||||||
|
#define hifi_ContextOverlayInterface_h
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
#include <PointerEvent.h>
|
||||||
|
#include <ui/TabletScriptingInterface.h>
|
||||||
|
#include "avatar/AvatarManager.h"
|
||||||
|
|
||||||
|
#include "EntityScriptingInterface.h"
|
||||||
|
#include "ui/overlays/Image3DOverlay.h"
|
||||||
|
#include "ui/overlays/Overlays.h"
|
||||||
|
#include "scripting/HMDScriptingInterface.h"
|
||||||
|
|
||||||
|
#include "EntityTree.h"
|
||||||
|
#include "ContextOverlayLogging.h"
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* @namespace ContextOverlay
|
||||||
|
*/
|
||||||
|
class ContextOverlayInterface : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QUuid entityWithContextOverlay READ getCurrentEntityWithContextOverlay WRITE setCurrentEntityWithContextOverlay)
|
||||||
|
Q_PROPERTY(bool enabled READ getEnabled WRITE setEnabled)
|
||||||
|
Q_PROPERTY(bool isInMarketplaceInspectionMode READ getIsInMarketplaceInspectionMode WRITE setIsInMarketplaceInspectionMode)
|
||||||
|
QSharedPointer<EntityScriptingInterface> _entityScriptingInterface;
|
||||||
|
EntityPropertyFlags _entityPropertyFlags;
|
||||||
|
QSharedPointer<HMDScriptingInterface> _hmdScriptingInterface;
|
||||||
|
QSharedPointer<TabletScriptingInterface> _tabletScriptingInterface;
|
||||||
|
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
|
||||||
|
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
|
||||||
|
public:
|
||||||
|
ContextOverlayInterface();
|
||||||
|
|
||||||
|
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
|
||||||
|
void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; }
|
||||||
|
void setEnabled(bool enabled);
|
||||||
|
bool getEnabled() { return _enabled; }
|
||||||
|
bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; }
|
||||||
|
void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
||||||
|
bool destroyContextOverlay(const EntityItemID& entityItemID);
|
||||||
|
void contextOverlays_mousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
void contextOverlays_hoverEnterOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
void contextOverlays_hoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
void contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event);
|
||||||
|
void contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event);
|
||||||
|
bool contextOverlayFilterPassed(const EntityItemID& entityItemID);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _verboseLogging { true };
|
||||||
|
bool _enabled { true };
|
||||||
|
QUuid _currentEntityWithContextOverlay{};
|
||||||
|
QString _entityMarketplaceID;
|
||||||
|
bool _contextOverlayJustClicked { false };
|
||||||
|
|
||||||
|
bool _isInMarketplaceInspectionMode { false };
|
||||||
|
|
||||||
|
Setting::Handle<bool> _settingSwitch { "inspectionMode", false };
|
||||||
|
|
||||||
|
void openMarketplace();
|
||||||
|
void enableEntityHighlight(const EntityItemID& entityItemID);
|
||||||
|
void disableEntityHighlight(const EntityItemID& entityItemID);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_ContextOverlayInterface_h
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// HoverOverlayLogging.cpp
|
// ContextOverlayLogging.cpp
|
||||||
// libraries/entities/src
|
// interface/src/ui/overlays
|
||||||
//
|
//
|
||||||
// Created by Zach Fox on 2017-07-17
|
// Created by Zach Fox on 2017-07-17
|
||||||
// Copyright 2017 High Fidelity, Inc.
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
@ -9,6 +9,6 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "HoverOverlayLogging.h"
|
#include "ContextOverlayLogging.h"
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(hover_overlay, "hifi.hover_overlay")
|
Q_LOGGING_CATEGORY(context_overlay, "hifi.context_overlay")
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// HoverOverlayLogging.h
|
// ContextOverlayLogging.h
|
||||||
// libraries/entities/src
|
// interface/src/ui/overlays
|
||||||
//
|
//
|
||||||
// Created by Zach Fox on 2017-07-17
|
// Created by Zach Fox on 2017-07-17
|
||||||
// Copyright 2017 High Fidelity, Inc.
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
@ -10,11 +10,11 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef hifi_HoverOverlayLogging_h
|
#ifndef hifi_ContextOverlayLogging_h
|
||||||
#define hifi_HoverOverlayLogging_h
|
#define hifi_ContextOverlayLogging_h
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(hover_overlay)
|
Q_DECLARE_LOGGING_CATEGORY(context_overlay)
|
||||||
|
|
||||||
#endif // hifi_HoverOverlayLogging_h
|
#endif // hifi_ContextOverlayLogging_h
|
|
@ -20,7 +20,7 @@ Overlay::Overlay() :
|
||||||
_renderItemID(render::Item::INVALID_ITEM_ID),
|
_renderItemID(render::Item::INVALID_ITEM_ID),
|
||||||
_isLoaded(true),
|
_isLoaded(true),
|
||||||
_alpha(DEFAULT_ALPHA),
|
_alpha(DEFAULT_ALPHA),
|
||||||
_pulse(0.0f),
|
_pulse(1.0f),
|
||||||
_pulseMax(0.0f),
|
_pulseMax(0.0f),
|
||||||
_pulseMin(0.0f),
|
_pulseMin(0.0f),
|
||||||
_pulsePeriod(1.0f),
|
_pulsePeriod(1.0f),
|
||||||
|
|
|
@ -116,7 +116,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
|
||||||
|
|
||||||
QMutexLocker locker(&_mutex);
|
QMutexLocker locker(&_mutex);
|
||||||
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
|
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
|
||||||
|
|
||||||
// Reset all batch pipeline settings between overlay
|
// Reset all batch pipeline settings between overlay
|
||||||
geometryCache->useSimpleDrawPipeline(batch);
|
geometryCache->useSimpleDrawPipeline(batch);
|
||||||
batch.setResourceTexture(0, textureCache->getWhiteTexture()); // FIXME - do we really need to do this??
|
batch.setResourceTexture(0, textureCache->getWhiteTexture()); // FIXME - do we really need to do this??
|
||||||
|
@ -136,7 +136,7 @@ void Overlays::enable() {
|
||||||
_enabled = true;
|
_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder
|
// Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder
|
||||||
// class on packet processing threads
|
// class on packet processing threads
|
||||||
Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
|
Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
|
||||||
QMutexLocker locker(&_mutex);
|
QMutexLocker locker(&_mutex);
|
||||||
|
@ -244,8 +244,8 @@ OverlayID Overlays::cloneOverlay(OverlayID id) {
|
||||||
|
|
||||||
bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
|
bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
// NOTE editOverlay can be called very frequently in scripts and can't afford to
|
// NOTE editOverlay can be called very frequently in scripts and can't afford to
|
||||||
// block waiting on the main thread. Additionally, no script actually
|
// block waiting on the main thread. Additionally, no script actually
|
||||||
// examines the return value and does something useful with it, so use a non-blocking
|
// examines the return value and does something useful with it, so use a non-blocking
|
||||||
// invoke and just always return true
|
// invoke and just always return true
|
||||||
QMetaObject::invokeMethod(this, "editOverlay", Q_ARG(OverlayID, id), Q_ARG(QVariant, properties));
|
QMetaObject::invokeMethod(this, "editOverlay", Q_ARG(OverlayID, id), Q_ARG(QVariant, properties));
|
||||||
|
@ -705,27 +705,27 @@ bool Overlays::isAddedOverlay(OverlayID id) {
|
||||||
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
|
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event) {
|
void Overlays::sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||||
QMetaObject::invokeMethod(this, "mousePressOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
QMetaObject::invokeMethod(this, "mousePressOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::sendMouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event) {
|
void Overlays::sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||||
QMetaObject::invokeMethod(this, "mouseReleaseOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
QMetaObject::invokeMethod(this, "mouseReleaseOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::sendMouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event) {
|
void Overlays::sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event) {
|
||||||
QMetaObject::invokeMethod(this, "mouseMoveOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
QMetaObject::invokeMethod(this, "mouseMoveOnOverlay", Q_ARG(OverlayID, overlayID), Q_ARG(PointerEvent, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::sendHoverEnterOverlay(OverlayID id, PointerEvent event) {
|
void Overlays::sendHoverEnterOverlay(const OverlayID& id, const PointerEvent& event) {
|
||||||
QMetaObject::invokeMethod(this, "hoverEnterOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
QMetaObject::invokeMethod(this, "hoverEnterOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::sendHoverOverOverlay(OverlayID id, PointerEvent event) {
|
void Overlays::sendHoverOverOverlay(const OverlayID& id, const PointerEvent& event) {
|
||||||
QMetaObject::invokeMethod(this, "hoverOverOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
QMetaObject::invokeMethod(this, "hoverOverOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::sendHoverLeaveOverlay(OverlayID id, PointerEvent event) {
|
void Overlays::sendHoverLeaveOverlay(const OverlayID& id, const PointerEvent& event) {
|
||||||
QMetaObject::invokeMethod(this, "hoverLeaveOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
QMetaObject::invokeMethod(this, "hoverLeaveOverlay", Q_ARG(OverlayID, id), Q_ARG(PointerEvent, event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,7 +775,7 @@ float Overlays::height() {
|
||||||
|
|
||||||
static const uint32_t MOUSE_POINTER_ID = 0;
|
static const uint32_t MOUSE_POINTER_ID = 0;
|
||||||
|
|
||||||
static glm::vec2 projectOntoOverlayXYPlane(glm::vec3 position, glm::quat rotation, glm::vec2 dimensions, const PickRay& pickRay,
|
static glm::vec2 projectOntoOverlayXYPlane(glm::vec3 position, glm::quat rotation, glm::vec2 dimensions, const PickRay& pickRay,
|
||||||
const RayToOverlayIntersectionResult& rayPickResult) {
|
const RayToOverlayIntersectionResult& rayPickResult) {
|
||||||
|
|
||||||
// Project the intersection point onto the local xy plane of the overlay.
|
// Project the intersection point onto the local xy plane of the overlay.
|
||||||
|
@ -818,15 +818,20 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay ray,
|
PointerEvent Overlays::calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray,
|
||||||
RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event,
|
RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event,
|
||||||
PointerEvent::EventType eventType) {
|
PointerEvent::EventType eventType) {
|
||||||
|
auto overlay = std::dynamic_pointer_cast<Planar3DOverlay>(getOverlay(overlayID));
|
||||||
|
if (getOverlayType(overlayID) == "web3d") {
|
||||||
|
overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(overlayID));
|
||||||
|
}
|
||||||
|
if (!overlay) {
|
||||||
|
return PointerEvent();
|
||||||
|
}
|
||||||
|
glm::vec3 position = overlay->getPosition();
|
||||||
|
glm::quat rotation = overlay->getRotation();
|
||||||
|
glm::vec2 dimensions = overlay->getSize();
|
||||||
|
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(overlay);
|
|
||||||
|
|
||||||
auto position = thisOverlay->getPosition();
|
|
||||||
auto rotation = thisOverlay->getRotation();
|
|
||||||
auto dimensions = thisOverlay->getSize();
|
|
||||||
|
|
||||||
glm::vec2 pos2D = projectOntoOverlayXYPlane(position, rotation, dimensions, ray, rayPickResult);
|
glm::vec2 pos2D = projectOntoOverlayXYPlane(position, rotation, dimensions, ray, rayPickResult);
|
||||||
|
|
||||||
|
@ -874,13 +879,9 @@ bool Overlays::mousePressEvent(QMouseEvent* event) {
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||||
|
|
||||||
// Only Web overlays can have focus.
|
PointerEvent pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press);
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentClickingOnOverlayID));
|
emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
||||||
if (thisOverlay) {
|
return true;
|
||||||
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press);
|
|
||||||
emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
emit mousePressOffOverlay();
|
emit mousePressOffOverlay();
|
||||||
return false;
|
return false;
|
||||||
|
@ -894,13 +895,9 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) {
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
_currentClickingOnOverlayID = rayPickResult.overlayID;
|
||||||
|
|
||||||
// Only Web overlays can have focus.
|
auto pointerEvent = calculateOverlayPointerEvent(_currentClickingOnOverlayID, ray, rayPickResult, event, PointerEvent::Press);
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentClickingOnOverlayID));
|
emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
||||||
if (thisOverlay) {
|
return true;
|
||||||
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press);
|
|
||||||
emit mouseDoublePressOnOverlay(_currentClickingOnOverlayID, pointerEvent);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
emit mouseDoublePressOffOverlay();
|
emit mouseDoublePressOffOverlay();
|
||||||
return false;
|
return false;
|
||||||
|
@ -912,13 +909,8 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) {
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
|
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release);
|
||||||
// Only Web overlays can have focus.
|
emit mouseReleaseOnOverlay(rayPickResult.overlayID, pointerEvent);
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(rayPickResult.overlayID));
|
|
||||||
if (thisOverlay) {
|
|
||||||
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Release);
|
|
||||||
emit mouseReleaseOnOverlay(rayPickResult.overlayID, pointerEvent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID;
|
_currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID;
|
||||||
|
@ -931,40 +923,29 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) {
|
||||||
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
PickRay ray = qApp->computePickRay(event->x(), event->y());
|
||||||
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray);
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
|
auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||||
|
emit mouseMoveOnOverlay(rayPickResult.overlayID, pointerEvent);
|
||||||
|
|
||||||
// Only Web overlays can have focus.
|
// If previously hovering over a different overlay then leave hover on that overlay.
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(rayPickResult.overlayID));
|
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID && rayPickResult.overlayID != _currentHoverOverOverlayID) {
|
||||||
if (thisOverlay) {
|
auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||||
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Move);
|
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
|
||||||
emit mouseMoveOnOverlay(rayPickResult.overlayID, pointerEvent);
|
|
||||||
|
|
||||||
// If previously hovering over a different overlay then leave hover on that overlay.
|
|
||||||
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID && rayPickResult.overlayID != _currentHoverOverOverlayID) {
|
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentHoverOverOverlayID));
|
|
||||||
if (thisOverlay) {
|
|
||||||
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Move);
|
|
||||||
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If hovering over a new overlay then enter hover on that overlay.
|
|
||||||
if (rayPickResult.overlayID != _currentHoverOverOverlayID) {
|
|
||||||
emit hoverEnterOverlay(rayPickResult.overlayID, pointerEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hover over current overlay.
|
|
||||||
emit hoverOverOverlay(rayPickResult.overlayID, pointerEvent);
|
|
||||||
|
|
||||||
_currentHoverOverOverlayID = rayPickResult.overlayID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If hovering over a new overlay then enter hover on that overlay.
|
||||||
|
if (rayPickResult.overlayID != _currentHoverOverOverlayID) {
|
||||||
|
emit hoverEnterOverlay(rayPickResult.overlayID, pointerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hover over current overlay.
|
||||||
|
emit hoverOverOverlay(rayPickResult.overlayID, pointerEvent);
|
||||||
|
|
||||||
|
_currentHoverOverOverlayID = rayPickResult.overlayID;
|
||||||
} else {
|
} else {
|
||||||
// If previously hovering an overlay then leave hover.
|
// If previously hovering an overlay then leave hover.
|
||||||
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID) {
|
if (_currentHoverOverOverlayID != UNKNOWN_OVERLAY_ID) {
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlay(_currentHoverOverOverlayID));
|
auto pointerEvent = calculateOverlayPointerEvent(_currentHoverOverOverlayID, ray, rayPickResult, event, PointerEvent::Move);
|
||||||
if (thisOverlay) {
|
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
|
||||||
auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Move);
|
|
||||||
emit hoverLeaveOverlay(_currentHoverOverOverlayID, pointerEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID;
|
_currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ public slots:
|
||||||
OverlayID cloneOverlay(OverlayID id);
|
OverlayID cloneOverlay(OverlayID id);
|
||||||
|
|
||||||
/**jsdoc
|
/**jsdoc
|
||||||
* Edit an overlay's properties.
|
* Edit an overlay's properties.
|
||||||
*
|
*
|
||||||
* @function Overlays.editOverlay
|
* @function Overlays.editOverlay
|
||||||
* @param {Overlays.OverlayID} overlayID The ID of the overlay to edit.
|
* @param {Overlays.OverlayID} overlayID The ID of the overlay to edit.
|
||||||
|
@ -288,13 +288,13 @@ public slots:
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void sendMousePressOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void sendMousePressOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
void sendMouseReleaseOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void sendMouseReleaseOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
void sendMouseMoveOnOverlay(OverlayID overlayID, const PointerEvent& event);
|
void sendMouseMoveOnOverlay(const OverlayID& overlayID, const PointerEvent& event);
|
||||||
|
|
||||||
void sendHoverEnterOverlay(OverlayID id, PointerEvent event);
|
void sendHoverEnterOverlay(const OverlayID& id, const PointerEvent& event);
|
||||||
void sendHoverOverOverlay(OverlayID id, PointerEvent event);
|
void sendHoverOverOverlay(const OverlayID& id, const PointerEvent& event);
|
||||||
void sendHoverLeaveOverlay(OverlayID id, PointerEvent event);
|
void sendHoverLeaveOverlay(const OverlayID& id, const PointerEvent& event);
|
||||||
|
|
||||||
OverlayID getKeyboardFocusOverlay();
|
OverlayID getKeyboardFocusOverlay();
|
||||||
void setKeyboardFocusOverlay(OverlayID id);
|
void setKeyboardFocusOverlay(OverlayID id);
|
||||||
|
@ -337,7 +337,7 @@ private:
|
||||||
#endif
|
#endif
|
||||||
bool _enabled = true;
|
bool _enabled = true;
|
||||||
|
|
||||||
PointerEvent calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, RayToOverlayIntersectionResult rayPickResult,
|
PointerEvent calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray, RayToOverlayIntersectionResult rayPickResult,
|
||||||
QMouseEvent* event, PointerEvent::EventType eventType);
|
QMouseEvent* event, PointerEvent::EventType eventType);
|
||||||
|
|
||||||
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
|
OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID };
|
||||||
|
|
|
@ -21,6 +21,7 @@ public:
|
||||||
Planar3DOverlay(const Planar3DOverlay* planar3DOverlay);
|
Planar3DOverlay(const Planar3DOverlay* planar3DOverlay);
|
||||||
|
|
||||||
virtual AABox getBounds() const override;
|
virtual AABox getBounds() const override;
|
||||||
|
virtual glm::vec2 getSize() const { return _dimensions; };
|
||||||
|
|
||||||
glm::vec2 getDimensions() const { return _dimensions; }
|
glm::vec2 getDimensions() const { return _dimensions; }
|
||||||
void setDimensions(float value) { _dimensions = glm::vec2(value); }
|
void setDimensions(float value) { _dimensions = glm::vec2(value); }
|
||||||
|
|
|
@ -597,7 +597,7 @@ void Web3DOverlay::setScriptURL(const QString& scriptURL) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 Web3DOverlay::getSize() {
|
glm::vec2 Web3DOverlay::getSize() const {
|
||||||
return _resolution / _dpi * INCHES_TO_METERS * getDimensions();
|
return _resolution / _dpi * INCHES_TO_METERS * getDimensions();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
void setProperties(const QVariantMap& properties) override;
|
void setProperties(const QVariantMap& properties) override;
|
||||||
QVariant getProperty(const QString& property) override;
|
QVariant getProperty(const QString& property) override;
|
||||||
|
|
||||||
glm::vec2 getSize();
|
glm::vec2 getSize() const override;
|
||||||
|
|
||||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <SceneScriptingInterface.h>
|
#include <SceneScriptingInterface.h>
|
||||||
#include <ScriptEngine.h>
|
#include <ScriptEngine.h>
|
||||||
#include <HoverOverlayInterface.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "RenderableEntityItem.h"
|
#include "RenderableEntityItem.h"
|
||||||
|
@ -453,8 +452,6 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
|
||||||
|
|
||||||
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
|
void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityScriptingInterface) {
|
||||||
|
|
||||||
auto hoverOverlayInterface = DependencyManager::get<HoverOverlayInterface>().data();
|
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
|
connect(this, &EntityTreeRenderer::mousePressOnEntity, entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity);
|
||||||
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
|
connect(this, &EntityTreeRenderer::mouseMoveOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseMoveOnEntity);
|
||||||
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
|
connect(this, &EntityTreeRenderer::mouseReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity);
|
||||||
|
@ -464,12 +461,8 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS
|
||||||
connect(this, &EntityTreeRenderer::clickReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickReleaseOnEntity);
|
connect(this, &EntityTreeRenderer::clickReleaseOnEntity, entityScriptingInterface, &EntityScriptingInterface::clickReleaseOnEntity);
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::hoverEnterEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity);
|
connect(this, &EntityTreeRenderer::hoverEnterEntity, entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity);
|
||||||
connect(this, SIGNAL(hoverEnterEntity(const EntityItemID&, const PointerEvent&)), hoverOverlayInterface, SLOT(createHoverOverlay(const EntityItemID&, const PointerEvent&)));
|
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::hoverOverEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
|
connect(this, &EntityTreeRenderer::hoverOverEntity, entityScriptingInterface, &EntityScriptingInterface::hoverOverEntity);
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::hoverLeaveEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
|
connect(this, &EntityTreeRenderer::hoverLeaveEntity, entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity);
|
||||||
connect(this, SIGNAL(hoverLeaveEntity(const EntityItemID&, const PointerEvent&)), hoverOverlayInterface, SLOT(destroyHoverOverlay(const EntityItemID&, const PointerEvent&)));
|
|
||||||
|
|
||||||
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
|
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
|
||||||
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
|
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
|
||||||
|
@ -682,7 +675,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
|
||||||
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||||
|
|
||||||
bool precisionPicking = false; // for mouse moves we do not do precision picking
|
bool precisionPicking = true; // for mouse moves we do precision picking
|
||||||
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
|
RayToEntityIntersectionResult rayPickResult = findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking);
|
||||||
if (rayPickResult.intersects) {
|
if (rayPickResult.intersects) {
|
||||||
|
|
||||||
|
|
|
@ -372,6 +372,21 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
_model->updateRenderItems();
|
_model->updateRenderItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this simple logic should say we set showingEntityHighlight to true whenever we are in marketplace mode and we have a marketplace id, or
|
||||||
|
// whenever we are not set to none and shouldHighlight is true.
|
||||||
|
bool showingEntityHighlight = ((bool)(args->_outlineFlags & (int)RenderArgs::RENDER_OUTLINE_MARKETPLACE_MODE) && getMarketplaceID().length() != 0) ||
|
||||||
|
(args->_outlineFlags != RenderArgs::RENDER_OUTLINE_NONE && getShouldHighlight());
|
||||||
|
if (showingEntityHighlight) {
|
||||||
|
static glm::vec4 yellowColor(1.0f, 1.0f, 0.0f, 1.0f);
|
||||||
|
gpu::Batch& batch = *args->_batch;
|
||||||
|
bool success;
|
||||||
|
auto shapeTransform = getTransformToCenter(success);
|
||||||
|
if (success) {
|
||||||
|
batch.setModelTransform(shapeTransform); // we want to include the scale as well
|
||||||
|
DependencyManager::get<GeometryCache>()->renderWireCubeInstance(args, batch, yellowColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasModel() || (_model && _model->didVisualGeometryRequestFail())) {
|
if (!hasModel() || (_model && _model->didVisualGeometryRequestFail())) {
|
||||||
static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
|
static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||||
gpu::Batch& batch = *args->_batch;
|
gpu::Batch& batch = *args->_batch;
|
||||||
|
|
|
@ -133,6 +133,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
|
||||||
requestedProperties += PROP_LOCKED;
|
requestedProperties += PROP_LOCKED;
|
||||||
requestedProperties += PROP_USER_DATA;
|
requestedProperties += PROP_USER_DATA;
|
||||||
requestedProperties += PROP_MARKETPLACE_ID;
|
requestedProperties += PROP_MARKETPLACE_ID;
|
||||||
|
requestedProperties += PROP_SHOULD_HIGHLIGHT;
|
||||||
requestedProperties += PROP_NAME;
|
requestedProperties += PROP_NAME;
|
||||||
requestedProperties += PROP_HREF;
|
requestedProperties += PROP_HREF;
|
||||||
requestedProperties += PROP_DESCRIPTION;
|
requestedProperties += PROP_DESCRIPTION;
|
||||||
|
@ -278,6 +279,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
||||||
APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked());
|
APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData());
|
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID());
|
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, getShouldHighlight());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_NAME, getName());
|
APPEND_ENTITY_PROPERTY(PROP_NAME, getName());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL());
|
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_HREF, getHref());
|
APPEND_ENTITY_PROPERTY(PROP_HREF, getHref());
|
||||||
|
@ -829,6 +831,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT) {
|
||||||
|
READ_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, bool, setShouldHighlight);
|
||||||
|
}
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
|
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
|
||||||
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||||
READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
|
READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
|
||||||
|
@ -2803,6 +2809,20 @@ void EntityItem::setMarketplaceID(const QString& value) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityItem::getShouldHighlight() const {
|
||||||
|
bool result;
|
||||||
|
withReadLock([&] {
|
||||||
|
result = _shouldHighlight;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityItem::setShouldHighlight(const bool value) {
|
||||||
|
withWriteLock([&] {
|
||||||
|
_shouldHighlight = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t EntityItem::getDirtyFlags() const {
|
uint32_t EntityItem::getDirtyFlags() const {
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
|
|
|
@ -316,6 +316,9 @@ public:
|
||||||
QString getMarketplaceID() const;
|
QString getMarketplaceID() const;
|
||||||
void setMarketplaceID(const QString& value);
|
void setMarketplaceID(const QString& value);
|
||||||
|
|
||||||
|
bool getShouldHighlight() const;
|
||||||
|
void setShouldHighlight(const bool value);
|
||||||
|
|
||||||
// TODO: get rid of users of getRadius()...
|
// TODO: get rid of users of getRadius()...
|
||||||
float getRadius() const;
|
float getRadius() const;
|
||||||
|
|
||||||
|
@ -532,6 +535,7 @@ protected:
|
||||||
QString _userData;
|
QString _userData;
|
||||||
SimulationOwner _simulationOwner;
|
SimulationOwner _simulationOwner;
|
||||||
QString _marketplaceID;
|
QString _marketplaceID;
|
||||||
|
bool _shouldHighlight { false };
|
||||||
QString _name;
|
QString _name;
|
||||||
QString _href; //Hyperlink href
|
QString _href; //Hyperlink href
|
||||||
QString _description; //Hyperlink description
|
QString _description; //Hyperlink description
|
||||||
|
|
|
@ -289,6 +289,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
|
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
|
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
|
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_SHOULD_HIGHLIGHT, shouldHighlight);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_NAME, name);
|
CHECK_PROPERTY_CHANGE(PROP_NAME, name);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
|
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
|
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
|
||||||
|
@ -406,6 +407,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHOULD_HIGHLIGHT, shouldHighlight);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
|
||||||
|
|
||||||
|
@ -982,6 +984,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
||||||
ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float);
|
ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float);
|
||||||
ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
|
ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
|
||||||
ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
|
ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
|
||||||
|
ADD_PROPERTY_TO_MAP(PROP_SHOULD_HIGHLIGHT, ShouldHighlight, shouldHighlight, bool);
|
||||||
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
|
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
|
||||||
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
|
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
|
||||||
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
|
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
|
||||||
|
@ -1334,6 +1337,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
||||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape());
|
APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape());
|
||||||
}
|
}
|
||||||
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
|
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, properties.getShouldHighlight());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
|
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
|
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
|
||||||
|
@ -1632,6 +1636,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
||||||
}
|
}
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHOULD_HIGHLIGHT, bool, setShouldHighlight);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
|
||||||
|
@ -1746,6 +1751,7 @@ void EntityItemProperties::markAllChanged() {
|
||||||
//_alphaFinishChanged = true;
|
//_alphaFinishChanged = true;
|
||||||
|
|
||||||
_marketplaceIDChanged = true;
|
_marketplaceIDChanged = true;
|
||||||
|
_shouldHighlightChanged = true;
|
||||||
|
|
||||||
_keyLight.markAllChanged();
|
_keyLight.markAllChanged();
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,7 @@ public:
|
||||||
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH);
|
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH);
|
||||||
DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL);
|
DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL);
|
||||||
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID);
|
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID);
|
||||||
|
DEFINE_PROPERTY_REF(PROP_SHOULD_HIGHLIGHT, ShouldHighlight, shouldHighlight, bool, ENTITY_ITEM_DEFAULT_SHOULD_HIGHLIGHT);
|
||||||
DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup);
|
DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup);
|
||||||
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE);
|
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE);
|
||||||
DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray, PolyVoxEntityItem::DEFAULT_VOXEL_DATA);
|
DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray, PolyVoxEntityItem::DEFAULT_VOXEL_DATA);
|
||||||
|
|
|
@ -27,6 +27,7 @@ const glm::vec3 ENTITY_ITEM_HALF_VEC3 = glm::vec3(0.5f);
|
||||||
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
|
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
|
||||||
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
|
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
|
||||||
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
|
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
|
||||||
|
const bool ENTITY_ITEM_DEFAULT_SHOULD_HIGHLIGHT = false;
|
||||||
const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
|
const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
|
||||||
|
|
||||||
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
|
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
|
||||||
|
|
|
@ -78,6 +78,7 @@ enum EntityPropertyList {
|
||||||
|
|
||||||
PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities
|
PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities
|
||||||
PROP_MARKETPLACE_ID, // all entities
|
PROP_MARKETPLACE_ID, // all entities
|
||||||
|
PROP_SHOULD_HIGHLIGHT, // all entities
|
||||||
PROP_ACCELERATION, // all entities
|
PROP_ACCELERATION, // all entities
|
||||||
PROP_SIMULATION_OWNER, // formerly known as PROP_SIMULATOR_ID
|
PROP_SIMULATION_OWNER, // formerly known as PROP_SIMULATOR_ID
|
||||||
PROP_NAME, // all entities
|
PROP_NAME, // all entities
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// HoverOverlayInterface.cpp
|
|
||||||
// libraries/entities/src
|
|
||||||
//
|
|
||||||
// Created by Zach Fox on 2017-07-14.
|
|
||||||
// Copyright 2017 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 "HoverOverlayInterface.h"
|
|
||||||
|
|
||||||
HoverOverlayInterface::HoverOverlayInterface() {
|
|
||||||
// "hover_overlay" debug log category disabled by default.
|
|
||||||
// Create your own "qtlogging.ini" file and set your "QT_LOGGING_CONF" environment variable
|
|
||||||
// if you'd like to enable/disable certain categories.
|
|
||||||
// More details: http://doc.qt.io/qt-5/qloggingcategory.html#configuring-categories
|
|
||||||
QLoggingCategory::setFilterRules(QStringLiteral("hifi.hover_overlay.debug=false"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void HoverOverlayInterface::createHoverOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
|
||||||
qCDebug(hover_overlay) << "Creating Hover Overlay on top of entity with ID: " << entityItemID;
|
|
||||||
setCurrentHoveredEntity(entityItemID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HoverOverlayInterface::createHoverOverlay(const EntityItemID& entityItemID) {
|
|
||||||
HoverOverlayInterface::createHoverOverlay(entityItemID, PointerEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
void HoverOverlayInterface::destroyHoverOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
|
||||||
qCDebug(hover_overlay) << "Destroying Hover Overlay on top of entity with ID: " << entityItemID;
|
|
||||||
setCurrentHoveredEntity(QUuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
void HoverOverlayInterface::destroyHoverOverlay(const EntityItemID& entityItemID) {
|
|
||||||
HoverOverlayInterface::destroyHoverOverlay(entityItemID, PointerEvent());
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
//
|
|
||||||
// HoverOverlayInterface.h
|
|
||||||
// libraries/entities/src
|
|
||||||
//
|
|
||||||
// Created by Zach Fox on 2017-07-14.
|
|
||||||
// Copyright 2017 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
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#ifndef hifi_HoverOverlayInterface_h
|
|
||||||
#define hifi_HoverOverlayInterface_h
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
|
||||||
#include <PointerEvent.h>
|
|
||||||
|
|
||||||
#include "EntityTree.h"
|
|
||||||
#include "HoverOverlayLogging.h"
|
|
||||||
|
|
||||||
/**jsdoc
|
|
||||||
* @namespace HoverOverlay
|
|
||||||
*/
|
|
||||||
class HoverOverlayInterface : public QObject, public Dependency {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
Q_PROPERTY(QUuid currentHoveredEntity READ getCurrentHoveredEntity WRITE setCurrentHoveredEntity)
|
|
||||||
public:
|
|
||||||
HoverOverlayInterface();
|
|
||||||
|
|
||||||
Q_INVOKABLE QUuid getCurrentHoveredEntity() { return _currentHoveredEntity; }
|
|
||||||
void setCurrentHoveredEntity(const QUuid& entityID) { _currentHoveredEntity = entityID; }
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void createHoverOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
|
||||||
void createHoverOverlay(const EntityItemID& entityItemID);
|
|
||||||
void destroyHoverOverlay(const EntityItemID& entityItemID, const PointerEvent& event);
|
|
||||||
void destroyHoverOverlay(const EntityItemID& entityItemID);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool _verboseLogging { true };
|
|
||||||
QUuid _currentHoveredEntity{};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_HoverOverlayInterface_h
|
|
|
@ -236,6 +236,7 @@ controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInp
|
||||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Shift), "Shift"));
|
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Shift), "Shift"));
|
||||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
|
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString()));
|
||||||
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
|
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString()));
|
||||||
|
availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Tab), QKeySequence(Qt::Key_Tab).toString()));
|
||||||
|
|
||||||
availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseButton"));
|
availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseButton"));
|
||||||
availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseButton"));
|
availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseButton"));
|
||||||
|
|
|
@ -62,7 +62,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::EntityEdit:
|
case PacketType::EntityEdit:
|
||||||
case PacketType::EntityData:
|
case PacketType::EntityData:
|
||||||
case PacketType::EntityPhysics:
|
case PacketType::EntityPhysics:
|
||||||
return VERSION_ENTITIES_BULLET_DYNAMICS;
|
return VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT;
|
||||||
case PacketType::EntityQuery:
|
case PacketType::EntityQuery:
|
||||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree);
|
return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree);
|
||||||
case PacketType::AvatarIdentity:
|
case PacketType::AvatarIdentity:
|
||||||
|
|
|
@ -218,6 +218,7 @@ const PacketVersion VERSION_ENTITIES_PHYSICS_PACKET = 67;
|
||||||
const PacketVersion VERSION_ENTITIES_ZONE_FILTERS = 68;
|
const PacketVersion VERSION_ENTITIES_ZONE_FILTERS = 68;
|
||||||
const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69;
|
const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69;
|
||||||
const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70;
|
const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70;
|
||||||
|
const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71;
|
||||||
|
|
||||||
enum class EntityQueryPacketVersion: PacketVersion {
|
enum class EntityQueryPacketVersion: PacketVersion {
|
||||||
JSONFilter = 18,
|
JSONFilter = 18,
|
||||||
|
|
|
@ -63,6 +63,12 @@ namespace render {
|
||||||
public:
|
public:
|
||||||
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE };
|
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE };
|
||||||
enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD };
|
enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD };
|
||||||
|
enum OutlineFlags {
|
||||||
|
RENDER_OUTLINE_NONE = 0,
|
||||||
|
RENDER_OUTLINE_WIREFRAMES = 1,
|
||||||
|
RENDER_OUTLINE_MARKETPLACE_MODE = 2,
|
||||||
|
RENDER_OUTLINE_SHADER = 4
|
||||||
|
};
|
||||||
enum DebugFlags {
|
enum DebugFlags {
|
||||||
RENDER_DEBUG_NONE = 0,
|
RENDER_DEBUG_NONE = 0,
|
||||||
RENDER_DEBUG_HULLS = 1
|
RENDER_DEBUG_HULLS = 1
|
||||||
|
@ -112,6 +118,7 @@ namespace render {
|
||||||
int _boundaryLevelAdjust { 0 };
|
int _boundaryLevelAdjust { 0 };
|
||||||
RenderMode _renderMode { DEFAULT_RENDER_MODE };
|
RenderMode _renderMode { DEFAULT_RENDER_MODE };
|
||||||
DisplayMode _displayMode { MONO };
|
DisplayMode _displayMode { MONO };
|
||||||
|
OutlineFlags _outlineFlags{ RENDER_OUTLINE_NONE };
|
||||||
DebugFlags _debugFlags { RENDER_DEBUG_NONE };
|
DebugFlags _debugFlags { RENDER_DEBUG_NONE };
|
||||||
gpu::Batch* _batch = nullptr;
|
gpu::Batch* _batch = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,10 @@ var DEFAULT_GRABBABLE_DATA = {
|
||||||
var USE_BLACKLIST = true;
|
var USE_BLACKLIST = true;
|
||||||
var blacklist = [];
|
var blacklist = [];
|
||||||
|
|
||||||
var entitiesWithHoverOverlays = [];
|
var hoveredEntityID = false;
|
||||||
|
var contextOverlayTimer = false;
|
||||||
|
var entityWithContextOverlay = false;
|
||||||
|
var contextualHand = -1;
|
||||||
|
|
||||||
var FORBIDDEN_GRAB_NAMES = ["Grab Debug Entity", "grab pointer"];
|
var FORBIDDEN_GRAB_NAMES = ["Grab Debug Entity", "grab pointer"];
|
||||||
var FORBIDDEN_GRAB_TYPES = ["Unknown", "Light", "PolyLine", "Zone"];
|
var FORBIDDEN_GRAB_TYPES = ["Unknown", "Light", "PolyLine", "Zone"];
|
||||||
|
@ -224,6 +227,7 @@ CONTROLLER_STATE_MACHINE[STATE_OFF] = {
|
||||||
CONTROLLER_STATE_MACHINE[STATE_SEARCHING] = {
|
CONTROLLER_STATE_MACHINE[STATE_SEARCHING] = {
|
||||||
name: "searching",
|
name: "searching",
|
||||||
enterMethod: "searchEnter",
|
enterMethod: "searchEnter",
|
||||||
|
exitMethod: "searchExit",
|
||||||
updateMethod: "search"
|
updateMethod: "search"
|
||||||
};
|
};
|
||||||
CONTROLLER_STATE_MACHINE[STATE_DISTANCE_HOLDING] = {
|
CONTROLLER_STATE_MACHINE[STATE_DISTANCE_HOLDING] = {
|
||||||
|
@ -351,7 +355,9 @@ function projectOntoXYPlane(worldPos, position, rotation, dimensions, registrati
|
||||||
|
|
||||||
function projectOntoEntityXYPlane(entityID, worldPos) {
|
function projectOntoEntityXYPlane(entityID, worldPos) {
|
||||||
var props = entityPropertiesCache.getProps(entityID);
|
var props = entityPropertiesCache.getProps(entityID);
|
||||||
return projectOntoXYPlane(worldPos, props.position, props.rotation, props.dimensions, props.registrationPoint);
|
if (props) {
|
||||||
|
return projectOntoXYPlane(worldPos, props.position, props.rotation, props.dimensions, props.registrationPoint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function projectOntoOverlayXYPlane(overlayID, worldPos) {
|
function projectOntoOverlayXYPlane(overlayID, worldPos) {
|
||||||
|
@ -369,7 +375,9 @@ function projectOntoOverlayXYPlane(overlayID, worldPos) {
|
||||||
dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale);
|
dimensions = Vec3.multiplyVbyV(Vec3.multiply(resolution, INCHES_TO_METERS / dpi), scale);
|
||||||
} else {
|
} else {
|
||||||
dimensions = Overlays.getProperty(overlayID, "dimensions");
|
dimensions = Overlays.getProperty(overlayID, "dimensions");
|
||||||
dimensions.z = 0.01; // overlay dimensions are 2D, not 3D.
|
if (dimensions.z) {
|
||||||
|
dimensions.z = 0.01; // overlay dimensions are 2D, not 3D.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT);
|
return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT);
|
||||||
|
@ -2191,6 +2199,14 @@ function MyController(hand) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.searchExit = function () {
|
||||||
|
contextualHand = -1;
|
||||||
|
if (hoveredEntityID) {
|
||||||
|
Entities.sendHoverLeaveEntity(hoveredEntityID, pointerEvent);
|
||||||
|
}
|
||||||
|
hoveredEntityID = false;
|
||||||
|
};
|
||||||
|
|
||||||
this.search = function(deltaTime, timestamp) {
|
this.search = function(deltaTime, timestamp) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
var name;
|
var name;
|
||||||
|
@ -2220,13 +2236,63 @@ function MyController(hand) {
|
||||||
entityPropertiesCache.addEntity(rayPickInfo.entityID);
|
entityPropertiesCache.addEntity(rayPickInfo.entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rayPickInfo.entityID && entitiesWithHoverOverlays.indexOf(rayPickInfo.entityID) == -1) {
|
pointerEvent = {
|
||||||
entitiesWithHoverOverlays.forEach(function (element) {
|
type: "Move",
|
||||||
HoverOverlay.destroyHoverOverlay(element);
|
id: this.hand + 1, // 0 is reserved for hardware mouse
|
||||||
});
|
pos2D: projectOntoEntityXYPlane(rayPickInfo.entityID, rayPickInfo.intersection),
|
||||||
entitiesWithHoverOverlays = [];
|
pos3D: rayPickInfo.intersection,
|
||||||
HoverOverlay.createHoverOverlay(rayPickInfo.entityID);
|
normal: rayPickInfo.normal,
|
||||||
entitiesWithHoverOverlays.push(rayPickInfo.entityID);
|
direction: rayPickInfo.searchRay.direction,
|
||||||
|
button: "None"
|
||||||
|
};
|
||||||
|
if (rayPickInfo.entityID) {
|
||||||
|
if (hoveredEntityID !== rayPickInfo.entityID) {
|
||||||
|
if (contextOverlayTimer) {
|
||||||
|
Script.clearTimeout(contextOverlayTimer);
|
||||||
|
contextOverlayTimer = false;
|
||||||
|
}
|
||||||
|
if (hoveredEntityID) {
|
||||||
|
Entities.sendHoverLeaveEntity(hoveredEntityID, pointerEvent);
|
||||||
|
}
|
||||||
|
hoveredEntityID = rayPickInfo.entityID;
|
||||||
|
Entities.sendHoverEnterEntity(hoveredEntityID, pointerEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we already have a context overlay, we don't want to move it to
|
||||||
|
// another entity while we're searching.
|
||||||
|
if (!entityWithContextOverlay && !contextOverlayTimer) {
|
||||||
|
contextOverlayTimer = Script.setTimeout(function () {
|
||||||
|
if (rayPickInfo.entityID === hoveredEntityID &&
|
||||||
|
!entityWithContextOverlay &&
|
||||||
|
contextualHand !== -1 &&
|
||||||
|
contextOverlayTimer) {
|
||||||
|
var pointerEvent = {
|
||||||
|
type: "Move",
|
||||||
|
id: contextualHand + 1, // 0 is reserved for hardware mouse
|
||||||
|
pos2D: projectOntoEntityXYPlane(rayPickInfo.entityID, rayPickInfo.intersection),
|
||||||
|
pos3D: rayPickInfo.intersection,
|
||||||
|
normal: rayPickInfo.normal,
|
||||||
|
direction: rayPickInfo.searchRay.direction,
|
||||||
|
button: "Secondary"
|
||||||
|
};
|
||||||
|
if (ContextOverlay.createOrDestroyContextOverlay(rayPickInfo.entityID, pointerEvent)) {
|
||||||
|
entityWithContextOverlay = rayPickInfo.entityID;
|
||||||
|
hoveredEntityID = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contextOverlayTimer = false;
|
||||||
|
}, 500);
|
||||||
|
contextualHand = this.hand;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (hoveredEntityID) {
|
||||||
|
Entities.sendHoverLeaveEntity(hoveredEntityID, pointerEvent);
|
||||||
|
hoveredEntityID = false;
|
||||||
|
}
|
||||||
|
if (contextOverlayTimer) {
|
||||||
|
Script.clearTimeout(contextOverlayTimer);
|
||||||
|
contextOverlayTimer = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var candidateHotSpotEntities = Entities.findEntities(handPosition, MAX_EQUIP_HOTSPOT_RADIUS);
|
var candidateHotSpotEntities = Entities.findEntities(handPosition, MAX_EQUIP_HOTSPOT_RADIUS);
|
||||||
|
@ -2433,8 +2499,11 @@ function MyController(hand) {
|
||||||
button: "None"
|
button: "None"
|
||||||
};
|
};
|
||||||
|
|
||||||
this.hoverEntity = entity;
|
if (this.hoverEntity !== entity) {
|
||||||
Entities.sendHoverEnterEntity(entity, pointerEvent);
|
Entities.sendHoverLeaveEntity(this.hoverEntity, pointerEvent);
|
||||||
|
this.hoverEntity = entity;
|
||||||
|
Entities.sendHoverEnterEntity(this.hoverEntity, pointerEvent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send mouse events for button highlights and tooltips.
|
// send mouse events for button highlights and tooltips.
|
||||||
|
@ -2483,25 +2552,25 @@ function MyController(hand) {
|
||||||
var pointerEvent;
|
var pointerEvent;
|
||||||
if (rayPickInfo.overlayID) {
|
if (rayPickInfo.overlayID) {
|
||||||
var overlay = rayPickInfo.overlayID;
|
var overlay = rayPickInfo.overlayID;
|
||||||
if (Overlays.getProperty(overlay, "type") != "web3d") {
|
if ((Overlays.getProperty(overlay, "type") === "web3d") && Overlays.keyboardFocusOverlay != overlay) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (Overlays.keyboardFocusOverlay != overlay) {
|
|
||||||
Entities.keyboardFocusEntity = null;
|
Entities.keyboardFocusEntity = null;
|
||||||
Overlays.keyboardFocusOverlay = overlay;
|
Overlays.keyboardFocusOverlay = overlay;
|
||||||
|
}
|
||||||
|
|
||||||
pointerEvent = {
|
pointerEvent = {
|
||||||
type: "Move",
|
type: "Move",
|
||||||
id: HARDWARE_MOUSE_ID,
|
id: HARDWARE_MOUSE_ID,
|
||||||
pos2D: projectOntoOverlayXYPlane(overlay, rayPickInfo.intersection),
|
pos2D: projectOntoOverlayXYPlane(overlay, rayPickInfo.intersection),
|
||||||
pos3D: rayPickInfo.intersection,
|
pos3D: rayPickInfo.intersection,
|
||||||
normal: rayPickInfo.normal,
|
normal: rayPickInfo.normal,
|
||||||
direction: rayPickInfo.searchRay.direction,
|
direction: rayPickInfo.searchRay.direction,
|
||||||
button: "None"
|
button: "None"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.hoverOverlay !== overlay) {
|
||||||
|
Overlays.sendHoverLeaveOverlay(this.hoverOverlay, pointerEvent);
|
||||||
this.hoverOverlay = overlay;
|
this.hoverOverlay = overlay;
|
||||||
Overlays.sendHoverEnterOverlay(overlay, pointerEvent);
|
Overlays.sendHoverEnterOverlay(this.hoverOverlay, pointerEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send mouse events for button highlights and tooltips.
|
// Send mouse events for button highlights and tooltips.
|
||||||
|
@ -3477,6 +3546,15 @@ function MyController(hand) {
|
||||||
var existingSearchDistance = this.searchSphereDistance;
|
var existingSearchDistance = this.searchSphereDistance;
|
||||||
this.release();
|
this.release();
|
||||||
|
|
||||||
|
if (hoveredEntityID) {
|
||||||
|
Entities.sendHoverLeaveEntity(hoveredEntityID, pointerEvent);
|
||||||
|
hoveredEntityID = false;
|
||||||
|
}
|
||||||
|
if (entityWithContextOverlay) {
|
||||||
|
ContextOverlay.destroyContextOverlay(entityWithContextOverlay);
|
||||||
|
entityWithContextOverlay = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isInEditMode()) {
|
if (isInEditMode()) {
|
||||||
this.searchSphereDistance = existingSearchDistance;
|
this.searchSphereDistance = existingSearchDistance;
|
||||||
}
|
}
|
||||||
|
@ -3597,7 +3675,7 @@ function MyController(hand) {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.overlayLaserTouchingEnter = function () {
|
this.overlayLaserTouchingEnter = function () {
|
||||||
// Test for intersection between controller laser and Web overlay plane.
|
// Test for intersection between controller laser and overlay plane.
|
||||||
var controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
var controllerLocation = getControllerWorldLocation(this.handToController(), true);
|
||||||
var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation);
|
var intersectInfo = handLaserIntersectOverlay(this.grabbedOverlay, controllerLocation);
|
||||||
if (intersectInfo) {
|
if (intersectInfo) {
|
||||||
|
@ -3791,11 +3869,6 @@ function MyController(hand) {
|
||||||
this.release = function() {
|
this.release = function() {
|
||||||
this.turnOffVisualizations();
|
this.turnOffVisualizations();
|
||||||
|
|
||||||
entitiesWithHoverOverlays.forEach(function (element) {
|
|
||||||
HoverOverlay.destroyHoverOverlay(element);
|
|
||||||
});
|
|
||||||
entitiesWithHoverOverlays = [];
|
|
||||||
|
|
||||||
if (this.grabbedThingID !== null) {
|
if (this.grabbedThingID !== null) {
|
||||||
|
|
||||||
Messages.sendMessage('Hifi-Teleport-Ignore-Remove', this.grabbedThingID);
|
Messages.sendMessage('Hifi-Teleport-Ignore-Remove', this.grabbedThingID);
|
||||||
|
|
|
@ -394,7 +394,6 @@ var toolBar = (function () {
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
Script.scriptEnding.connect(cleanup);
|
Script.scriptEnding.connect(cleanup);
|
||||||
|
|
||||||
Window.domainChanged.connect(function () {
|
Window.domainChanged.connect(function () {
|
||||||
that.setActive(false);
|
that.setActive(false);
|
||||||
that.clearEntityList();
|
that.clearEntityList();
|
||||||
|
@ -622,6 +621,7 @@ var toolBar = (function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
that.setActive = function (active) {
|
that.setActive = function (active) {
|
||||||
|
ContextOverlay.enabled = !active;
|
||||||
Settings.setValue(EDIT_SETTING, active);
|
Settings.setValue(EDIT_SETTING, active);
|
||||||
if (active) {
|
if (active) {
|
||||||
Controller.captureEntityClickEvents();
|
Controller.captureEntityClickEvents();
|
||||||
|
@ -2194,6 +2194,7 @@ var PopupMenu = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
|
ContextOverlay.enabled = true;
|
||||||
for (var i = 0; i < overlays.length; i++) {
|
for (var i = 0; i < overlays.length; i++) {
|
||||||
Overlays.deleteOverlay(overlays[i]);
|
Overlays.deleteOverlay(overlays[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,135 +11,140 @@
|
||||||
/* global Tablet, Script, HMD, UserActivityLogger, Entities */
|
/* global Tablet, Script, HMD, UserActivityLogger, Entities */
|
||||||
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function () { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
Script.include("../libraries/WebTablet.js");
|
Script.include("../libraries/WebTablet.js");
|
||||||
|
|
||||||
var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace";
|
var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace";
|
||||||
var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page.
|
var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page.
|
||||||
var MARKETPLACES_URL = Script.resolvePath("../html/marketplaces.html");
|
var MARKETPLACES_URL = Script.resolvePath("../html/marketplaces.html");
|
||||||
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
|
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
|
||||||
|
|
||||||
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
|
var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
|
||||||
// var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
|
// var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-root.png";
|
||||||
|
|
||||||
// Event bridge messages.
|
// Event bridge messages.
|
||||||
var CLARA_IO_DOWNLOAD = "CLARA.IO DOWNLOAD";
|
var CLARA_IO_DOWNLOAD = "CLARA.IO DOWNLOAD";
|
||||||
var CLARA_IO_STATUS = "CLARA.IO STATUS";
|
var CLARA_IO_STATUS = "CLARA.IO STATUS";
|
||||||
var CLARA_IO_CANCEL_DOWNLOAD = "CLARA.IO CANCEL DOWNLOAD";
|
var CLARA_IO_CANCEL_DOWNLOAD = "CLARA.IO CANCEL DOWNLOAD";
|
||||||
var CLARA_IO_CANCELLED_DOWNLOAD = "CLARA.IO CANCELLED DOWNLOAD";
|
var CLARA_IO_CANCELLED_DOWNLOAD = "CLARA.IO CANCELLED DOWNLOAD";
|
||||||
var GOTO_DIRECTORY = "GOTO_DIRECTORY";
|
var GOTO_DIRECTORY = "GOTO_DIRECTORY";
|
||||||
var QUERY_CAN_WRITE_ASSETS = "QUERY_CAN_WRITE_ASSETS";
|
var QUERY_CAN_WRITE_ASSETS = "QUERY_CAN_WRITE_ASSETS";
|
||||||
var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS";
|
var CAN_WRITE_ASSETS = "CAN_WRITE_ASSETS";
|
||||||
var WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS";
|
var WARN_USER_NO_PERMISSIONS = "WARN_USER_NO_PERMISSIONS";
|
||||||
|
|
||||||
var CLARA_DOWNLOAD_TITLE = "Preparing Download";
|
var CLARA_DOWNLOAD_TITLE = "Preparing Download";
|
||||||
var messageBox = null;
|
var messageBox = null;
|
||||||
var isDownloadBeingCancelled = false;
|
var isDownloadBeingCancelled = false;
|
||||||
|
|
||||||
var CANCEL_BUTTON = 4194304; // QMessageBox::Cancel
|
var CANCEL_BUTTON = 4194304; // QMessageBox::Cancel
|
||||||
var NO_BUTTON = 0; // QMessageBox::NoButton
|
var NO_BUTTON = 0; // QMessageBox::NoButton
|
||||||
|
|
||||||
var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't write to \nthe domain's Asset Server.";
|
var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't write to \nthe domain's Asset Server.";
|
||||||
|
|
||||||
function onMessageBoxClosed(id, button) {
|
function onMessageBoxClosed(id, button) {
|
||||||
if (id === messageBox && button === CANCEL_BUTTON) {
|
if (id === messageBox && button === CANCEL_BUTTON) {
|
||||||
isDownloadBeingCancelled = true;
|
isDownloadBeingCancelled = true;
|
||||||
messageBox = null;
|
messageBox = null;
|
||||||
tablet.emitScriptEvent(CLARA_IO_CANCEL_DOWNLOAD);
|
tablet.emitScriptEvent(CLARA_IO_CANCEL_DOWNLOAD);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Window.messageBoxClosed.connect(onMessageBoxClosed);
|
Window.messageBoxClosed.connect(onMessageBoxClosed);
|
||||||
|
|
||||||
var onMarketplaceScreen = false;
|
var onMarketplaceScreen = false;
|
||||||
|
|
||||||
function showMarketplace() {
|
function showMarketplace() {
|
||||||
UserActivityLogger.openedMarketplace();
|
UserActivityLogger.openedMarketplace();
|
||||||
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
tablet.webEventReceived.connect(function (message) {
|
tablet.webEventReceived.connect(function (message) {
|
||||||
|
|
||||||
if (message === GOTO_DIRECTORY) {
|
if (message === GOTO_DIRECTORY) {
|
||||||
tablet.gotoWebScreen(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
tablet.gotoWebScreen(MARKETPLACES_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message === QUERY_CAN_WRITE_ASSETS) {
|
if (message === QUERY_CAN_WRITE_ASSETS) {
|
||||||
tablet.emitScriptEvent(CAN_WRITE_ASSETS + " " + Entities.canWriteAssets());
|
tablet.emitScriptEvent(CAN_WRITE_ASSETS + " " + Entities.canWriteAssets());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message === WARN_USER_NO_PERMISSIONS) {
|
if (message === WARN_USER_NO_PERMISSIONS) {
|
||||||
Window.alert(NO_PERMISSIONS_ERROR_MESSAGE);
|
Window.alert(NO_PERMISSIONS_ERROR_MESSAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.slice(0, CLARA_IO_STATUS.length) === CLARA_IO_STATUS) {
|
if (message.slice(0, CLARA_IO_STATUS.length) === CLARA_IO_STATUS) {
|
||||||
if (isDownloadBeingCancelled) {
|
if (isDownloadBeingCancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = message.slice(CLARA_IO_STATUS.length);
|
||||||
|
if (messageBox === null) {
|
||||||
|
messageBox = Window.openMessageBox(CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON);
|
||||||
|
} else {
|
||||||
|
Window.updateMessageBox(messageBox, CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var text = message.slice(CLARA_IO_STATUS.length);
|
if (message.slice(0, CLARA_IO_DOWNLOAD.length) === CLARA_IO_DOWNLOAD) {
|
||||||
if (messageBox === null) {
|
if (messageBox !== null) {
|
||||||
messageBox = Window.openMessageBox(CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON);
|
Window.closeMessageBox(messageBox);
|
||||||
} else {
|
messageBox = null;
|
||||||
Window.updateMessageBox(messageBox, CLARA_DOWNLOAD_TITLE, text, CANCEL_BUTTON, NO_BUTTON);
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.slice(0, CLARA_IO_DOWNLOAD.length) === CLARA_IO_DOWNLOAD) {
|
if (message === CLARA_IO_CANCELLED_DOWNLOAD) {
|
||||||
if (messageBox !== null) {
|
isDownloadBeingCancelled = false;
|
||||||
Window.closeMessageBox(messageBox);
|
|
||||||
messageBox = null;
|
|
||||||
}
|
}
|
||||||
return;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message === CLARA_IO_CANCELLED_DOWNLOAD) {
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
isDownloadBeingCancelled = false;
|
var marketplaceButton = tablet.addButton({
|
||||||
}
|
icon: "icons/tablet-icons/market-i.svg",
|
||||||
|
activeIcon: "icons/tablet-icons/market-a.svg",
|
||||||
|
text: "MARKET",
|
||||||
|
sortOrder: 9
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
function onCanWriteAssetsChanged() {
|
||||||
var marketplaceButton = tablet.addButton({
|
var message = CAN_WRITE_ASSETS + " " + Entities.canWriteAssets();
|
||||||
icon: "icons/tablet-icons/market-i.svg",
|
tablet.emitScriptEvent(message);
|
||||||
activeIcon: "icons/tablet-icons/market-a.svg",
|
|
||||||
text: "MARKET",
|
|
||||||
sortOrder: 9
|
|
||||||
});
|
|
||||||
|
|
||||||
function onCanWriteAssetsChanged() {
|
|
||||||
var message = CAN_WRITE_ASSETS + " " + Entities.canWriteAssets();
|
|
||||||
tablet.emitScriptEvent(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onClick() {
|
|
||||||
if (onMarketplaceScreen) {
|
|
||||||
// for toolbar-mode: go back to home screen, this will close the window.
|
|
||||||
tablet.gotoHomeScreen();
|
|
||||||
} else {
|
|
||||||
var entity = HMD.tabletID;
|
|
||||||
Entities.editEntity(entity, {textures: JSON.stringify({"tex.close": HOME_BUTTON_TEXTURE})});
|
|
||||||
showMarketplace();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function onScreenChanged(type, url) {
|
function onClick() {
|
||||||
onMarketplaceScreen = type === "Web" && url === MARKETPLACE_URL_INITIAL
|
if (onMarketplaceScreen) {
|
||||||
// for toolbar mode: change button to active when window is first openend, false otherwise.
|
// for toolbar-mode: go back to home screen, this will close the window.
|
||||||
marketplaceButton.editProperties({isActive: onMarketplaceScreen});
|
tablet.gotoHomeScreen();
|
||||||
}
|
} else {
|
||||||
|
var entity = HMD.tabletID;
|
||||||
marketplaceButton.clicked.connect(onClick);
|
Entities.editEntity(entity, { textures: JSON.stringify({ "tex.close": HOME_BUTTON_TEXTURE }) });
|
||||||
tablet.screenChanged.connect(onScreenChanged);
|
showMarketplace();
|
||||||
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
|
}
|
||||||
|
|
||||||
Script.scriptEnding.connect(function () {
|
|
||||||
if (onMarketplaceScreen) {
|
|
||||||
tablet.gotoHomeScreen();
|
|
||||||
}
|
}
|
||||||
tablet.removeButton(marketplaceButton);
|
|
||||||
tablet.screenChanged.disconnect(onScreenChanged);
|
function onScreenChanged(type, url) {
|
||||||
Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged);
|
onMarketplaceScreen = type === "Web" && url === MARKETPLACE_URL_INITIAL
|
||||||
});
|
// for toolbar mode: change button to active when window is first openend, false otherwise.
|
||||||
|
marketplaceButton.editProperties({ isActive: onMarketplaceScreen });
|
||||||
|
if (type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1) {
|
||||||
|
ContextOverlay.isInMarketplaceInspectionMode = true;
|
||||||
|
} else {
|
||||||
|
ContextOverlay.isInMarketplaceInspectionMode = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
marketplaceButton.clicked.connect(onClick);
|
||||||
|
tablet.screenChanged.connect(onScreenChanged);
|
||||||
|
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
if (onMarketplaceScreen) {
|
||||||
|
tablet.gotoHomeScreen();
|
||||||
|
}
|
||||||
|
tablet.removeButton(marketplaceButton);
|
||||||
|
tablet.screenChanged.disconnect(onScreenChanged);
|
||||||
|
Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged);
|
||||||
|
});
|
||||||
|
|
||||||
}()); // END LOCAL_SCOPE
|
}()); // END LOCAL_SCOPE
|
||||||
|
|
|
@ -710,6 +710,7 @@ function off() {
|
||||||
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
||||||
tablet.tabletShownChanged.disconnect(tabletVisibilityChanged);
|
tablet.tabletShownChanged.disconnect(tabletVisibilityChanged);
|
||||||
isWired = false;
|
isWired = false;
|
||||||
|
ContextOverlay.enabled = true
|
||||||
}
|
}
|
||||||
if (audioTimer) {
|
if (audioTimer) {
|
||||||
Script.clearInterval(audioTimer);
|
Script.clearInterval(audioTimer);
|
||||||
|
@ -722,6 +723,7 @@ function off() {
|
||||||
|
|
||||||
function tabletVisibilityChanged() {
|
function tabletVisibilityChanged() {
|
||||||
if (!tablet.tabletShown) {
|
if (!tablet.tabletShown) {
|
||||||
|
ContextOverlay.enabled = true;
|
||||||
tablet.gotoHomeScreen();
|
tablet.gotoHomeScreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -732,7 +734,9 @@ function onTabletButtonClicked() {
|
||||||
if (onPalScreen) {
|
if (onPalScreen) {
|
||||||
// for toolbar-mode: go back to home screen, this will close the window.
|
// for toolbar-mode: go back to home screen, this will close the window.
|
||||||
tablet.gotoHomeScreen();
|
tablet.gotoHomeScreen();
|
||||||
|
ContextOverlay.enabled = true;
|
||||||
} else {
|
} else {
|
||||||
|
ContextOverlay.enabled = false;
|
||||||
tablet.loadQMLSource(PAL_QML_SOURCE);
|
tablet.loadQMLSource(PAL_QML_SOURCE);
|
||||||
tablet.tabletShownChanged.connect(tabletVisibilityChanged);
|
tablet.tabletShownChanged.connect(tabletVisibilityChanged);
|
||||||
Users.requestsDomainListData = true;
|
Users.requestsDomainListData = true;
|
||||||
|
@ -863,6 +867,7 @@ function avatarDisconnected(nodeID) {
|
||||||
function clearLocalQMLDataAndClosePAL() {
|
function clearLocalQMLDataAndClosePAL() {
|
||||||
sendToQml({ method: 'clearLocalQMLData' });
|
sendToQml({ method: 'clearLocalQMLData' });
|
||||||
if (onPalScreen) {
|
if (onPalScreen) {
|
||||||
|
ContextOverlay.enabled = true;
|
||||||
tablet.gotoHomeScreen();
|
tablet.gotoHomeScreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,6 @@
|
||||||
|
|
||||||
function showTabletUI() {
|
function showTabletUI() {
|
||||||
checkTablet()
|
checkTablet()
|
||||||
gTablet.tabletShown = true;
|
|
||||||
|
|
||||||
if (!tabletRezzed || !tabletIsValid()) {
|
if (!tabletRezzed || !tabletIsValid()) {
|
||||||
closeTabletUI();
|
closeTabletUI();
|
||||||
|
@ -123,6 +122,7 @@
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, { visible: true });
|
Overlays.editOverlay(HMD.tabletScreenID, { visible: true });
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 });
|
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 });
|
||||||
}
|
}
|
||||||
|
gTablet.tabletShown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideTabletUI() {
|
function hideTabletUI() {
|
||||||
|
|
Loading…
Reference in a new issue