From ee2936d13345fe22a357bbd826c0cdc378cc0dbe Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 18 Jan 2018 14:07:07 +1300 Subject: [PATCH 01/33] Add Pointers API function that disables hover events for nominated items --- interface/src/raypick/PointerScriptingInterface.cpp | 4 ++++ interface/src/raypick/PointerScriptingInterface.h | 8 ++++++++ libraries/pointers/src/Pointer.cpp | 11 +++++++++++ libraries/pointers/src/Pointer.h | 3 +++ libraries/pointers/src/PointerManager.cpp | 7 +++++++ libraries/pointers/src/PointerManager.h | 1 + 6 files changed, 34 insertions(+) diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index ac5a467e76..8e50b1d629 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -24,6 +24,10 @@ void PointerScriptingInterface::setIncludeItems(unsigned int uid, const QScriptV DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } +void PointerScriptingInterface::setNonHoverItems(unsigned int uid, const QScriptValue& nonHoverItems) const { + DependencyManager::get()->setNonHoverItems(uid, qVectorQUuidFromScriptValue(nonHoverItems)); +} + unsigned int PointerScriptingInterface::createPointer(const PickQuery::PickType& type, const QVariant& properties) { // Interaction with managers should always happen on the main thread if (QThread::currentThread() != qApp->thread()) { diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 1cc7b56503..4791fd802e 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -191,6 +191,14 @@ public: */ Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const; + /**jsdoc + * Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs that the pointer should not send hover events to. + * @function Pointers.setNonHoverItems + * @param {number} uid - The ID of the Pointer, as returned by {@link Pointers.createPointer}. + * @param {Uuid[]} nonHoverItems - A list of IDs to that hover events should not be sent to. + */ + Q_INVOKABLE void setNonHoverItems(unsigned int uid, const QScriptValue& nonHoverItems) const; + /**jsdoc * Lock a Pointer onto a specific object (overlay, entity, or avatar). Optionally, provide an offset in object-space, otherwise the Pointer will lock on to the center of the object. * Not used by Stylus Pointers. diff --git a/libraries/pointers/src/Pointer.cpp b/libraries/pointers/src/Pointer.cpp index 5307e17355..ead3c22687 100644 --- a/libraries/pointers/src/Pointer.cpp +++ b/libraries/pointers/src/Pointer.cpp @@ -52,6 +52,12 @@ void Pointer::setIncludeItems(const QVector& includeItems) const { DependencyManager::get()->setIncludeItems(_pickUID, includeItems); } +void Pointer::setNonHoverItems(const QVector& nonHoverItems) { + withWriteLock([&] { + _nonHoverItems = nonHoverItems; + }); +} + bool Pointer::isLeftHand() const { return DependencyManager::get()->isLeftHand(_pickUID); } @@ -96,6 +102,11 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin // Hover events bool doHover = shouldHover(pickResult); + + auto pickResultMap = pickResult->toVariantMap(); + auto uuid = QUuid(pickResultMap.value("objectID", "").toString()); + doHover = doHover && !_nonHoverItems.contains(uuid); + Pointer::PickedObject hoveredObject = getHoveredObject(pickResult); PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult); hoveredEvent.setType(PointerEvent::Move); diff --git a/libraries/pointers/src/Pointer.h b/libraries/pointers/src/Pointer.h index 3197c80cad..6cb366e92a 100644 --- a/libraries/pointers/src/Pointer.h +++ b/libraries/pointers/src/Pointer.h @@ -54,6 +54,8 @@ public: virtual void setIgnoreItems(const QVector& ignoreItems) const; virtual void setIncludeItems(const QVector& includeItems) const; + void setNonHoverItems(const QVector& nonHoverItems); + bool isLeftHand() const; bool isRightHand() const; bool isMouse() const; @@ -102,6 +104,7 @@ private: PointerEvent::Button chooseButton(const std::string& button); + QVector _nonHoverItems; }; #endif // hifi_Pick_h diff --git a/libraries/pointers/src/PointerManager.cpp b/libraries/pointers/src/PointerManager.cpp index be890da392..f2953ce8c8 100644 --- a/libraries/pointers/src/PointerManager.cpp +++ b/libraries/pointers/src/PointerManager.cpp @@ -108,6 +108,13 @@ void PointerManager::setIncludeItems(unsigned int uid, const QVector& inc } } +void PointerManager::setNonHoverItems(unsigned int uid, const QVector& nonHoverItems) const { + auto pointer = find(uid); + if (pointer) { + pointer->setNonHoverItems(nonHoverItems); + } +} + void PointerManager::setLength(unsigned int uid, float length) const { auto pointer = find(uid); if (pointer) { diff --git a/libraries/pointers/src/PointerManager.h b/libraries/pointers/src/PointerManager.h index b98558622f..a2a1e9dcd2 100644 --- a/libraries/pointers/src/PointerManager.h +++ b/libraries/pointers/src/PointerManager.h @@ -34,6 +34,7 @@ public: void setPrecisionPicking(unsigned int uid, bool precisionPicking) const; void setIgnoreItems(unsigned int uid, const QVector& ignoreEntities) const; void setIncludeItems(unsigned int uid, const QVector& includeEntities) const; + void setNonHoverItems(unsigned int uid, const QVector& nonHoverItems) const; void setLength(unsigned int uid, float length) const; void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const; From 5878e36ea8fc38c2c1e904e9398af9efa467c3da Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 18 Jan 2018 14:24:23 +1300 Subject: [PATCH 02/33] Display both lasers --- .../controllerModules/webSurfaceLaserInput.js | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 3d9d7979d5..19b5330492 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -87,20 +87,11 @@ Script.include("/~/system/libraries/controllers.js"); return MyAvatar.getDominantHand() === "right" ? 1 : 0; }; - this.dominantHandOverride = false; - this.isReady = function(controllerData) { - var otherModuleRunning = this.getOtherModule().running; - otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand. var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE && controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE; - if ((!otherModuleRunning || isTriggerPressed) - && (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData))) { + if (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData)) { this.updateAllwaysOn(); - if (isTriggerPressed) { - this.dominantHandOverride = true; // Override dominant hand. - this.getOtherModule().dominantHandOverride = false; - } if (this.parameters.handLaser.allwaysOn || isTriggerPressed) { return makeRunningValues(true, [], []); } @@ -109,11 +100,8 @@ Script.include("/~/system/libraries/controllers.js"); }; this.run = function(controllerData, deltaTime) { - var otherModuleRunning = this.getOtherModule().running; - otherModuleRunning = otherModuleRunning && this.getDominantHand() !== this.hand; // Auto-swap to dominant hand. - otherModuleRunning = otherModuleRunning || this.getOtherModule().dominantHandOverride; // Override dominant hand. var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData); - if (!otherModuleRunning && !grabModuleNeedsToRun && (controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE + if (!grabModuleNeedsToRun && (controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE || this.parameters.handLaser.allwaysOn && (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData)))) { this.running = true; @@ -121,7 +109,6 @@ Script.include("/~/system/libraries/controllers.js"); } this.deleteContextOverlay(); this.running = false; - this.dominantHandOverride = false; return makeRunningValues(false, [], []); }; } From 4eb2a5cf5e900a80abda46677038b0e88de53445 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 17 Jan 2018 19:25:20 -0800 Subject: [PATCH 03/33] added a property check in renderableModelEntity for the animation url this fixes the bug stopping you from changing animations on an entity --- .../src/RenderableModelEntityItem.cpp | 14 +++++++++++++- .../src/RenderableModelEntityItem.h | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 827507c3aa..684540453b 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1394,7 +1394,19 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce // That is where _currentFrame and _lastAnimated were updated. if (_animating) { DETAILED_PROFILE_RANGE(simulation_physics, "Animate"); - if (!jointsMapped()) { + // check animation url change + auto newprops = entity->getAnimationProperties(); + if (newprops != _previousAnimationProperties) { + if (newprops.getURL() != _previousAnimationProperties.getURL()) { + _animation = DependencyManager::get()->getAnimation(entity->getAnimationURL()); + _jointMappingCompleted = false; + mapJoints(entity, model->getJointNames()); + } + _previousAnimationProperties = newprops; + } + // + if (!jointsMapped() || _animation->getURL().toString() != entity->getAnimationURL()) { + qCDebug(entitiesrenderer) << "changed animation or started animation"; mapJoints(entity, model->getJointNames()); } if (!(entity->getAnimationFirstFrame() < 0) && !(entity->getAnimationFirstFrame() > entity->getAnimationLastFrame())) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index b3988e0239..ce4d44daf8 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -193,6 +193,9 @@ private: bool _animating { false }; uint64_t _lastAnimated { 0 }; + //fix test + AnimationPropertyGroup _previousAnimationProperties; + render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; }; From 403dd3d7d029a73c63e5e1c4f101d40efeff06ce Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 18 Jan 2018 22:31:12 +1300 Subject: [PATCH 04/33] Only first laser highlights --- .../controllers/controllerDispatcher.js | 64 +++++++++++++++++++ .../controllerModules/webSurfaceLaserInput.js | 45 ++++++++++++- 2 files changed, 107 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 16f1d086b7..15b025a7ea 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -44,7 +44,12 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.highVarianceCount = 0; this.veryhighVarianceCount = 0; this.tabletID = null; + this.TABLET_UI_UUIDS = []; this.blacklist = []; + this.leftPointerNonHoverItem = null; + this.leftPointerNonHoverItemChanged = false; + this.rightPointerNonHoverItem = null; + this.rightPointerNonHoverItemChanged = false; this.pointerManager = new PointerManager(); // a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are @@ -122,6 +127,10 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); return getControllerWorldLocation(Controller.Standard.RightHand, true); }; + this.isTabletID = function (uuid) { + return _this.TABLET_UI_UUIDS.indexOf(uuid) !== -1; + }; + this.updateTimings = function () { _this.intervalCount++; var thisInterval = Date.now(); @@ -148,11 +157,35 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.setIgnorePointerItems = function() { if (HMD.tabletID !== this.tabletID) { this.tabletID = HMD.tabletID; + this.TABLET_UI_UUIDS = [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID]; Pointers.setIgnoreItems(_this.leftPointer, _this.blacklist); Pointers.setIgnoreItems(_this.rightPointer, _this.blacklist); } }; + this.setNonHoverItems = function () { + if (_this.leftPointerNonHoverItemChanged) { + if (_this.leftPointerNonHoverItem === null) { + Pointers.setNonHoverItems(_this.leftPointer, []); + } else if (_this.isTabletID(_this.leftPointerNonHoverItem)) { + Pointers.setNonHoverItems(_this.leftPointer, _this.TABLET_UI_UUIDS); + } else { + Pointers.setNonHoverItems(_this.leftPointer, [_this.leftPointerNonHoverItem]); + } + _this.leftPointerNonHoverItemChanged = false; + } + if (_this.rightPointerNonHoverItemChanged) { + if (_this.rightPointerNonHoverItem === null) { + Pointers.setNonHoverItems(_this.rightPointer, []); + } else if (_this.isTabletID(_this.rightPointerNonHoverItem)) { + Pointers.setNonHoverItems(_this.rightPointer, _this.TABLET_UI_UUIDS); + } else { + Pointers.setNonHoverItems(_this.rightPointer, [_this.rightPointerNonHoverItem]); + } + _this.rightPointerNonHoverItemChanged = false; + } + }; + this.update = function () { try { _this.updateInternal(); @@ -324,6 +357,19 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); _this.runningPluginNames[orderedPluginName] = true; _this.markSlots(candidatePlugin, orderedPluginName); _this.pointerManager.makePointerVisible(candidatePlugin.parameters.handLaser); + + if (candidatePlugin.parameters.handLaser.nonHoverItem !== undefined) { + if (candidatePlugin.parameters.handLaser.hand === LEFT_HAND + && _this.leftPointerNonHoverItem !== candidatePlugin.parameters.handLaser.nonHoverItem) { + _this.leftPointerNonHoverItem = candidatePlugin.parameters.handLaser.nonHoverItem; + _this.leftPointerNonHoverItemChanged = true; + } else if (candidatePlugin.parameters.handLaser.hand === RIGHT_HAND + && _this.rightPointerNonHoverItem !== candidatePlugin.parameters.handLaser.nonHoverItem) { + _this.rightPointerNonHoverItem = candidatePlugin.parameters.handLaser.nonHoverItem; + _this.rightPointerNonHoverItemChanged = true; + } + } + if (DEBUG) { print("controllerDispatcher running " + orderedPluginName); } @@ -354,6 +400,21 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.beginProfileRange("dispatch.run." + runningPluginName); } var runningness = plugin.run(controllerData, deltaTime); + + if (runningness.active) { + if (plugin.parameters.handLaser.nonHoverItem !== undefined) { + if (plugin.parameters.handLaser.hand === LEFT_HAND + && _this.leftPointerNonHoverItem !== plugin.parameters.handLaser.nonHoverItem) { + _this.leftPointerNonHoverItem = plugin.parameters.handLaser.nonHoverItem; + _this.leftPointerNonHoverItemChanged = true; + } else if (plugin.parameters.handLaser.hand === RIGHT_HAND + && _this.rightPointerNonHoverItem !== plugin.parameters.handLaser.nonHoverItem) { + _this.rightPointerNonHoverItem = plugin.parameters.handLaser.nonHoverItem; + _this.rightPointerNonHoverItemChanged = true; + } + } + } + if (!runningness.active) { // plugin is finished running, for now. remove it from the list // of running plugins and mark its activity-slots as "not in use" @@ -372,6 +433,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } } _this.pointerManager.updatePointersRenderState(controllerData.triggerClicks, controllerData.triggerValues); + + _this.setNonHoverItems(); + if (PROFILE) { Script.endProfileRange("dispatch.run"); } diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 19b5330492..5b9afa3a2a 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -87,28 +87,69 @@ Script.include("/~/system/libraries/controllers.js"); return MyAvatar.getDominantHand() === "right" ? 1 : 0; }; + this.hoverItem = null; + + this.isTabletID = function (uuid) { + return [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHightlightID].indexOf(uuid) !== -1; + }; + this.isReady = function(controllerData) { var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE && controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE; if (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData)) { this.updateAllwaysOn(); if (this.parameters.handLaser.allwaysOn || isTriggerPressed) { + var pointingAt = controllerData.rayPicks[this.hand].objectID; + if (this.isTabletID(pointingAt)) { + pointingAt = HMD.tabletID; + } + + if (pointingAt !== this.getOtherModule().hoverItem) { + this.hoverItem = pointingAt; + this.getOtherModule().parameters.handLaser.nonHoverItem = pointingAt; + } else { + this.hoverItem = null; + this.getOtherModule().parameters.handLaser.nonHoverItem = null; + } + return makeRunningValues(true, [], []); } } + + this.hoverItem = null; + this.getOtherModule().parameters.handLaser.nonHoverItem = null; + return makeRunningValues(false, [], []); }; this.run = function(controllerData, deltaTime) { var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData); - if (!grabModuleNeedsToRun && (controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE - || this.parameters.handLaser.allwaysOn + var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE; + if (!grabModuleNeedsToRun && (isTriggerPressed || this.parameters.handLaser.allwaysOn && (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData)))) { this.running = true; + + var pointingAt = controllerData.rayPicks[this.hand].objectID; + if (this.isTabletID(pointingAt)) { + pointingAt = HMD.tabletID; + } + + if (pointingAt !== this.getOtherModule().hoverItem || isTriggerPressed) { + this.hoverItem = pointingAt; + this.getOtherModule().parameters.handLaser.nonHoverItem = pointingAt; + } else { + this.hoverItem = null; + this.getOtherModule().parameters.handLaser.nonHoverItem = null; + } + return makeRunningValues(true, [], []); } this.deleteContextOverlay(); this.running = false; + + this.hoverItem = null; + this.getOtherModule().parameters.handLaser.nonHoverItem = null; + return makeRunningValues(false, [], []); }; } From 9f484a7f57e870bf4d3691dce47d3cf80243571b Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 18 Jan 2018 08:54:05 -0800 Subject: [PATCH 05/33] Removed extraneous comments in RenderableItemEntity.cpp and .h --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 1 - libraries/entities-renderer/src/RenderableModelEntityItem.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 684540453b..cdbdd31d71 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1404,7 +1404,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce } _previousAnimationProperties = newprops; } - // if (!jointsMapped() || _animation->getURL().toString() != entity->getAnimationURL()) { qCDebug(entitiesrenderer) << "changed animation or started animation"; mapJoints(entity, model->getJointNames()); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index ce4d44daf8..014c5bbf67 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -192,8 +192,6 @@ private: bool _shouldHighlight { false }; bool _animating { false }; uint64_t _lastAnimated { 0 }; - - //fix test AnimationPropertyGroup _previousAnimationProperties; render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; From 1c97272767e3806c3fa9aa35d9474097c57e9934 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 18 Jan 2018 12:09:28 -0800 Subject: [PATCH 06/33] Cleaned up the code a bit so that there is no need for a new class variable for properties to verify the change of url --- .../src/RenderableModelEntityItem.cpp | 18 +++++++----------- .../src/RenderableModelEntityItem.h | 1 - 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index cdbdd31d71..8b5a23b787 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1394,18 +1394,14 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce // That is where _currentFrame and _lastAnimated were updated. if (_animating) { DETAILED_PROFILE_RANGE(simulation_physics, "Animate"); - // check animation url change - auto newprops = entity->getAnimationProperties(); - if (newprops != _previousAnimationProperties) { - if (newprops.getURL() != _previousAnimationProperties.getURL()) { - _animation = DependencyManager::get()->getAnimation(entity->getAnimationURL()); - _jointMappingCompleted = false; - mapJoints(entity, model->getJointNames()); - } - _previousAnimationProperties = newprops; + + if (!jointsMapped()) { + mapJoints(entity, model->getJointNames()); } - if (!jointsMapped() || _animation->getURL().toString() != entity->getAnimationURL()) { - qCDebug(entitiesrenderer) << "changed animation or started animation"; + //else the joints have been mapped before but we have new animation to load + else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) { + _animation = DependencyManager::get()->getAnimation(entity->getAnimationURL()); + _jointMappingCompleted = false; mapJoints(entity, model->getJointNames()); } if (!(entity->getAnimationFirstFrame() < 0) && !(entity->getAnimationFirstFrame() > entity->getAnimationLastFrame())) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 014c5bbf67..b3988e0239 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -192,7 +192,6 @@ private: bool _shouldHighlight { false }; bool _animating { false }; uint64_t _lastAnimated { 0 }; - AnimationPropertyGroup _previousAnimationProperties; render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() }; }; From a74b093b60c3541c96e541bba44d5d799361469e Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Thu, 11 Jan 2018 21:36:55 +0300 Subject: [PATCH 07/33] FB11109 Preview disabled image swap (Commerce only) --- .../resources/images/preview-privacy.png | Bin 0 -> 51845 bytes interface/src/Application.cpp | 3 ++ .../display-plugins/hmd/HmdDisplayPlugin.cpp | 14 ++---- libraries/ui/src/DesktopPreviewProvider.cpp | 45 ++++++++++++++++++ libraries/ui/src/DesktopPreviewProvider.h | 41 ++++++++++++++++ scripts/system/commerce/wallet.js | 8 +++- 6 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 interface/resources/images/preview-privacy.png create mode 100644 libraries/ui/src/DesktopPreviewProvider.cpp create mode 100644 libraries/ui/src/DesktopPreviewProvider.h diff --git a/interface/resources/images/preview-privacy.png b/interface/resources/images/preview-privacy.png new file mode 100644 index 0000000000000000000000000000000000000000..1a556b37f25f02cf0f3e1c1ec294725daef6cea1 GIT binary patch literal 51845 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 literal 0 HcmV?d00001 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6849bd07b5..85545e9def 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -209,6 +209,7 @@ #include "commerce/QmlCommerce.h" #include "webbrowser/WebBrowserSuggestionsEngine.h" +#include // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -632,6 +633,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(std::bind(&Application::getUserAgent, qApp)); DependencyManager::set(); DependencyManager::set(ScriptEngine::CLIENT_SCRIPT); @@ -5758,6 +5760,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerFunction("OverlayWindow", QmlWindowClass::constructor); scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); + scriptEngine->registerGlobalObject("DesktopPreviewProvider", DependencyManager::get().data()); scriptEngine->registerGlobalObject("Stats", Stats::getInstance()); scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Snapshot", DependencyManager::get().data()); diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 1d7fee38eb..90bb83a663 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -33,6 +33,7 @@ #include "../Logging.h" #include "../CompositorHelper.h" +#include "DesktopPreviewProvider.h" #include "render-utils/hmd_ui_vert.h" #include "render-utils/hmd_ui_frag.h" @@ -254,17 +255,9 @@ void HmdDisplayPlugin::internalPresent() { swapBuffers(); } else if (_clearPreviewFlag) { - QImage image; - if (_vsyncEnabled) { - image = QImage(PathUtils::resourcesPath() + "images/preview.png"); - } else { - image = QImage(PathUtils::resourcesPath() + "images/preview-disabled.png"); - } - image = image.mirrored(); - image = image.convertToFormat(QImage::Format_RGBA8888); - if (!_previewTexture) { - _previewTexture = gpu::Texture::createStrict( + QImage image = DesktopPreviewProvider::getInstance()->getPreviewDisabledImage(_vsyncEnabled); + _previewTexture = gpu::Texture::createStrict( gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA), image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, @@ -274,7 +267,6 @@ void HmdDisplayPlugin::internalPresent() { _previewTexture->setStoredMipFormat(gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); _previewTexture->assignStoredMip(0, image.byteCount(), image.constBits()); _previewTexture->setAutoGenerateMips(true); - } auto viewport = getViewportForSourceSize(uvec2(_previewTexture->getDimensions())); diff --git a/libraries/ui/src/DesktopPreviewProvider.cpp b/libraries/ui/src/DesktopPreviewProvider.cpp new file mode 100644 index 0000000000..4eeb058a57 --- /dev/null +++ b/libraries/ui/src/DesktopPreviewProvider.cpp @@ -0,0 +1,45 @@ +#include "DesktopPreviewProvider.h" +#include +#include +#include +#include + +DesktopPreviewProvider::DesktopPreviewProvider() { +} + +QSharedPointer DesktopPreviewProvider::getInstance() { + static QSharedPointer instance = DependencyManager::get(); + return instance; +} + +QImage DesktopPreviewProvider::getPreviewDisabledImage(bool vsyncEnabled) const { + + auto imageIndex = vsyncEnabled ? VSYNC : m_previewDisabledReason; + assert(imageIndex >= 0 && imageIndex <= VSYNC); + + static const QString imagePaths[] = { + "images/preview-disabled.png", // USER + "images/preview-privacy.png", // WALLET + "images/preview.png", // VSYNC + }; + + return !m_previewDisabled[imageIndex].isNull() ? m_previewDisabled[imageIndex] : loadPreviewImage(m_previewDisabled[imageIndex], PathUtils::resourcesPath() + imagePaths[imageIndex]); +} + +void DesktopPreviewProvider::setPreviewDisabledReason(PreviewDisabledReasons reason) { + m_previewDisabledReason = reason; +} + +void DesktopPreviewProvider::setPreviewDisabledReason(const QString& reasonString) { + PreviewDisabledReasons reason = USER; + bool ok = false; + + reason = (PreviewDisabledReasons) QMetaEnum::fromType().keyToValue(reasonString.toLatin1().data(), &ok); + if (ok) { + setPreviewDisabledReason(reason); + } +} + +QImage& DesktopPreviewProvider::loadPreviewImage(QImage& image, const QString& path) const { + return image = QImage(path).mirrored().convertToFormat(QImage::Format_RGBA8888); +} \ No newline at end of file diff --git a/libraries/ui/src/DesktopPreviewProvider.h b/libraries/ui/src/DesktopPreviewProvider.h new file mode 100644 index 0000000000..2204f26378 --- /dev/null +++ b/libraries/ui/src/DesktopPreviewProvider.h @@ -0,0 +1,41 @@ +// +// Created by Alexander Ivash on 2018/01/08 +// Copyright 2018 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 +#include + +class DesktopPreviewProvider : public QObject, public Dependency { + SINGLETON_DEPENDENCY + Q_OBJECT + + DesktopPreviewProvider(); + DesktopPreviewProvider(const DesktopPreviewProvider& other) = delete; +public: + enum PreviewDisabledReasons { + USER = 0, + SECURE_SCREEN + }; + Q_ENUM(PreviewDisabledReasons) + + int VSYNC { 2 }; + + static QSharedPointer DesktopPreviewProvider::getInstance(); + + QImage getPreviewDisabledImage(bool vsyncEnabled) const; + void setPreviewDisabledReason(PreviewDisabledReasons reason); + +public slots: + void setPreviewDisabledReason(const QString& reason); + +private: + QImage& loadPreviewImage(QImage& image, const QString& path) const; + + PreviewDisabledReasons m_previewDisabledReason = { USER }; + + mutable QImage m_previewDisabled[3]; +}; \ No newline at end of file diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 0826325a57..f93d6714f1 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -562,9 +562,11 @@ break; case 'disableHmdPreview': isHmdPreviewDisabled = Menu.isOptionChecked("Disable Preview"); + DesktopPreviewProvider.setPreviewDisabledReason("SECURE_SCREEN"); Menu.setIsOptionChecked("Disable Preview", true); break; case 'maybeEnableHmdPreview': + DesktopPreviewProvider.setPreviewDisabledReason("USER"); Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled); break; case 'passphraseReset': @@ -635,7 +637,11 @@ // -Called when the TabletScriptingInterface::screenChanged() signal is emitted. The "type" argument can be either the string // value of "Home", "Web", "Menu", "QML", or "Closed". The "url" argument is only valid for Web and QML. function onTabletScreenChanged(type, url) { - onWalletScreen = (type === "QML" && url === WALLET_QML_SOURCE); + var onWalletScreenNow = (type === "QML" && url === WALLET_QML_SOURCE); + if (!onWalletScreenNow && onWalletScreen) { + DesktopPreviewProvider.setPreviewDisabledReason("USER"); + } + onWalletScreen = onWalletScreenNow; wireEventBridge(onWalletScreen); // Change button to active when window is first openend, false otherwise. if (button) { From 744da710a313a18ad80fe16b5cd0b79f5a093ab4 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Tue, 16 Jan 2018 01:41:23 +0300 Subject: [PATCH 08/33] move VSYNC into 'PreviewDisabledReasons' enum --- libraries/ui/src/DesktopPreviewProvider.cpp | 4 ++++ libraries/ui/src/DesktopPreviewProvider.h | 5 ++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libraries/ui/src/DesktopPreviewProvider.cpp b/libraries/ui/src/DesktopPreviewProvider.cpp index 4eeb058a57..92a8d9e055 100644 --- a/libraries/ui/src/DesktopPreviewProvider.cpp +++ b/libraries/ui/src/DesktopPreviewProvider.cpp @@ -27,6 +27,10 @@ QImage DesktopPreviewProvider::getPreviewDisabledImage(bool vsyncEnabled) const } void DesktopPreviewProvider::setPreviewDisabledReason(PreviewDisabledReasons reason) { + if (reason == VSYNC) { + return; // Not settable via this interface, as VSYNC is controlled by HMD plugin.. + } + m_previewDisabledReason = reason; } diff --git a/libraries/ui/src/DesktopPreviewProvider.h b/libraries/ui/src/DesktopPreviewProvider.h index 2204f26378..40a4640f85 100644 --- a/libraries/ui/src/DesktopPreviewProvider.h +++ b/libraries/ui/src/DesktopPreviewProvider.h @@ -18,12 +18,11 @@ class DesktopPreviewProvider : public QObject, public Dependency { public: enum PreviewDisabledReasons { USER = 0, - SECURE_SCREEN + SECURE_SCREEN, + VSYNC // Not settable via this interface, as VSYNC is controlled by HMD plugin.. }; Q_ENUM(PreviewDisabledReasons) - int VSYNC { 2 }; - static QSharedPointer DesktopPreviewProvider::getInstance(); QImage getPreviewDisabledImage(bool vsyncEnabled) const; From 576ae227a86a9644962d82588028349116aa6b44 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Tue, 16 Jan 2018 01:51:46 +0300 Subject: [PATCH 09/33] move imagePaths into .h so simplify matching enum values to image files --- libraries/ui/src/DesktopPreviewProvider.cpp | 6 ------ libraries/ui/src/DesktopPreviewProvider.h | 7 +++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/ui/src/DesktopPreviewProvider.cpp b/libraries/ui/src/DesktopPreviewProvider.cpp index 92a8d9e055..d86e1f951f 100644 --- a/libraries/ui/src/DesktopPreviewProvider.cpp +++ b/libraries/ui/src/DesktopPreviewProvider.cpp @@ -17,12 +17,6 @@ QImage DesktopPreviewProvider::getPreviewDisabledImage(bool vsyncEnabled) const auto imageIndex = vsyncEnabled ? VSYNC : m_previewDisabledReason; assert(imageIndex >= 0 && imageIndex <= VSYNC); - static const QString imagePaths[] = { - "images/preview-disabled.png", // USER - "images/preview-privacy.png", // WALLET - "images/preview.png", // VSYNC - }; - return !m_previewDisabled[imageIndex].isNull() ? m_previewDisabled[imageIndex] : loadPreviewImage(m_previewDisabled[imageIndex], PathUtils::resourcesPath() + imagePaths[imageIndex]); } diff --git a/libraries/ui/src/DesktopPreviewProvider.h b/libraries/ui/src/DesktopPreviewProvider.h index 40a4640f85..db87009205 100644 --- a/libraries/ui/src/DesktopPreviewProvider.h +++ b/libraries/ui/src/DesktopPreviewProvider.h @@ -15,6 +15,13 @@ class DesktopPreviewProvider : public QObject, public Dependency { DesktopPreviewProvider(); DesktopPreviewProvider(const DesktopPreviewProvider& other) = delete; + + constexpr static char* imagePaths[] = { + "images/preview-disabled.png", // USER + "images/preview-privacy.png", // SECURE_SCREEN + "images/preview.png", // VSYNC + }; + public: enum PreviewDisabledReasons { USER = 0, From be3789e70a67e90f1fd921bdea1b88903948a506 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Tue, 16 Jan 2018 03:18:38 +0300 Subject: [PATCH 10/33] show warning on attempt to force 'VSYNC' preview reason --- libraries/ui/src/DesktopPreviewProvider.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/ui/src/DesktopPreviewProvider.cpp b/libraries/ui/src/DesktopPreviewProvider.cpp index d86e1f951f..4ae70a1eb0 100644 --- a/libraries/ui/src/DesktopPreviewProvider.cpp +++ b/libraries/ui/src/DesktopPreviewProvider.cpp @@ -22,6 +22,7 @@ QImage DesktopPreviewProvider::getPreviewDisabledImage(bool vsyncEnabled) const void DesktopPreviewProvider::setPreviewDisabledReason(PreviewDisabledReasons reason) { if (reason == VSYNC) { + qDebug() << "Preview disabled reason can't be forced to " << QMetaEnum::fromType().valueToKey(reason); return; // Not settable via this interface, as VSYNC is controlled by HMD plugin.. } From 29625953f6ec662e93585f014e2dfe68d5ef0616 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Wed, 17 Jan 2018 23:06:55 +0300 Subject: [PATCH 11/33] update privacy-specific disabled preview image --- .../resources/images/preview-privacy.png | Bin 51845 -> 52759 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/interface/resources/images/preview-privacy.png b/interface/resources/images/preview-privacy.png index 1a556b37f25f02cf0f3e1c1ec294725daef6cea1..1a718de23357eec659b05e590af7d1c2165d531c 100644 GIT binary patch literal 52759 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 literal 51845 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 From 50217726c0d026ce4412a5fcb8706562e91851cf Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Thu, 18 Jan 2018 22:29:07 +0300 Subject: [PATCH 12/33] remove extra qualification from DesktopPreviewProvider::getInstance() in .h --- libraries/ui/src/DesktopPreviewProvider.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui/src/DesktopPreviewProvider.h b/libraries/ui/src/DesktopPreviewProvider.h index db87009205..07d39a6cdf 100644 --- a/libraries/ui/src/DesktopPreviewProvider.h +++ b/libraries/ui/src/DesktopPreviewProvider.h @@ -30,7 +30,7 @@ public: }; Q_ENUM(PreviewDisabledReasons) - static QSharedPointer DesktopPreviewProvider::getInstance(); + static QSharedPointer getInstance(); QImage getPreviewDisabledImage(bool vsyncEnabled) const; void setPreviewDisabledReason(PreviewDisabledReasons reason); From 961ed88fb094515e95afd656ba2e920073cabfa5 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 18 Jan 2018 12:56:24 -0800 Subject: [PATCH 13/33] fixed coding standards in RenderableModelEntityItem.cpp --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8b5a23b787..fc1688974c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1397,9 +1397,8 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce if (!jointsMapped()) { mapJoints(entity, model->getJointNames()); - } - //else the joints have been mapped before but we have new animation to load - else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) { + //else the joint have been mapped before but we have a new animation to load + } else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) { _animation = DependencyManager::get()->getAnimation(entity->getAnimationURL()); _jointMappingCompleted = false; mapJoints(entity, model->getJointNames()); From a97b4b010dbc2c32089000d153fea86ac0209e47 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 18 Jan 2018 16:51:28 -0800 Subject: [PATCH 14/33] suppress Interface notification for DS decryption error --- scripts/system/notifications.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index 11c083dacc..728760c1e7 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -539,8 +539,14 @@ return startingUp; } - function onDomainConnectionRefused(reason) { - createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED); + function onDomainConnectionRefused(reason, reasonCode) { + // the "login error" reason means that the DS couldn't decrypt the username signature + // since this eventually resolves itself for good actors we don't need to show a notification for it + var LOGIN_ERROR_REASON_CODE = 2; + + if (reasonCode != LOGIN_ERROR_REASON_CODE) { + createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED); + } } function onEditError(msg) { From c6429f4f33b437109c46abc48347394b69545eb7 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 18 Jan 2018 17:05:36 -0800 Subject: [PATCH 15/33] Path towards pixel perfection --- .../resources/qml/controls-uit/TextField.qml | 22 ++++++-- .../wallet/sendMoney/ConnectionItem.qml | 18 +++---- .../commerce/wallet/sendMoney/SendMoney.qml | 52 ++++++++++++++----- scripts/system/commerce/wallet.js | 16 ++++-- 4 files changed, 79 insertions(+), 29 deletions(-) diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index b942c8b4ab..e2552c24d0 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -24,10 +24,13 @@ TextField { property bool isSearchField: false property string label: "" property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height + 1 : 0) + property bool hasDefocusedBorder: false; property bool hasRoundedBorder: false + property int roundedBorderRadius: 4 property bool error: false; property bool hasClearButton: false; - property string leftPlaceholderGlyph: ""; + property string leftPermanentGlyph: ""; + property string centerPlaceholderGlyph: ""; placeholderText: textField.placeholderText @@ -101,12 +104,12 @@ TextField { } } border.color: textField.error ? hifi.colors.redHighlight : - (textField.activeFocus ? hifi.colors.primaryHighlight : (isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray)) + (textField.activeFocus ? hifi.colors.primaryHighlight : (hasDefocusedBorder ? (isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray) : color)) border.width: textField.activeFocus || hasRoundedBorder || textField.error ? 1 : 0 - radius: isSearchField ? textField.height / 2 : (hasRoundedBorder ? 4 : 0) + radius: isSearchField ? textField.height / 2 : (hasRoundedBorder ? roundedBorderRadius : 0) HiFiGlyphs { - text: textField.leftPlaceholderGlyph; + text: textField.leftPermanentGlyph; color: textColor; size: hifi.fontSizes.textFieldSearchIcon; anchors.left: parent.left; @@ -115,6 +118,15 @@ TextField { visible: text; } + HiFiGlyphs { + text: textField.centerPlaceholderGlyph; + color: textColor; + size: parent.height; + anchors.horizontalCenter: parent.horizontalCenter; + anchors.verticalCenter: parent.verticalCenter; + visible: text && !textField.focus && textField.text === ""; + } + HiFiGlyphs { text: hifi.glyphs.search color: textColor @@ -145,7 +157,7 @@ TextField { placeholderTextColor: isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray selectedTextColor: hifi.colors.black selectionColor: hifi.colors.primaryHighlight - padding.left: ((isSearchField || textField.leftPlaceholderGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding + padding.left: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding padding.right: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding } diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/ConnectionItem.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/ConnectionItem.qml index c2d9ef3b19..33cd43bb05 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/ConnectionItem.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/ConnectionItem.qml @@ -29,13 +29,13 @@ Item { property string userName; property string profilePicUrl; - height: 65; + height: 75; width: parent.width; Rectangle { id: mainContainer; // Style - color: root.isSelected ? hifi.colors.faintGray : hifi.colors.white; + color: root.isSelected ? hifi.colors.faintGray80 : hifi.colors.white; // Size anchors.left: parent.left; anchors.right: parent.right; @@ -49,7 +49,7 @@ Item { anchors.verticalCenter: parent.verticalCenter; anchors.left: parent.left; anchors.leftMargin: 36; - height: root.height - 15; + height: 50; width: visible ? height : 0; clip: true; Image { @@ -83,15 +83,15 @@ Item { RalewaySemiBold { id: userName; anchors.left: avatarImage.right; - anchors.leftMargin: 16; + anchors.leftMargin: 12; anchors.top: parent.top; anchors.bottom: parent.bottom; anchors.right: chooseButton.visible ? chooseButton.left : parent.right; anchors.rightMargin: chooseButton.visible ? 10 : 0; // Text size - size: 20; + size: 18; // Style - color: hifi.colors.baseGray; + color: hifi.colors.blueAccent; text: root.userName; elide: Text.ElideRight; // Alignment @@ -107,9 +107,9 @@ Item { colorScheme: hifi.colorSchemes.dark; anchors.verticalCenter: parent.verticalCenter; anchors.right: parent.right; - anchors.rightMargin: 24; - height: root.height - 20; - width: 110; + anchors.rightMargin: 28; + height: 35; + width: 100; text: "CHOOSE"; onClicked: { var msg = { method: 'chooseConnection', userName: root.userName, profilePicUrl: root.profilePicUrl }; diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index 9164ba7a8c..905fb548b2 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -105,7 +105,8 @@ Item { // Send Money Home BEGIN Item { id: sendMoneyHome; - visible: root.currentActiveView === "sendMoneyHome"; + z: 996; + visible: root.currentActiveView === "sendMoneyHome" || root.currentActiveView === "chooseRecipientConnection" || root.currentActiveView === "chooseRecipientNearby"; anchors.fill: parent; anchors.topMargin: root.parentAppTitleBarHeight; anchors.bottomMargin: root.parentAppNavBarHeight; @@ -299,9 +300,18 @@ Item { // Choose Recipient Connection BEGIN Rectangle { id: chooseRecipientConnection; + z: 997; visible: root.currentActiveView === "chooseRecipientConnection"; anchors.fill: parent; - color: "#AAAAAA"; + color: "#80000000"; + + // This object is always used in a popup or full-screen Wallet section. + // This MouseArea is used to prevent a user from being + // able to click on a button/mouseArea underneath the popup/section. + MouseArea { + anchors.fill: parent; + propagateComposedEvents: false; + } ListModel { id: connectionsModel; @@ -314,6 +324,8 @@ Item { anchors.centerIn: parent; width: parent.width - 30; height: parent.height - 30; + color: "#FFFFFF"; + radius: 8; RalewaySemiBold { id: chooseRecipientText_connections; @@ -322,11 +334,11 @@ Item { anchors.top: parent.top; anchors.topMargin: 26; anchors.left: parent.left; - anchors.leftMargin: 20; + anchors.leftMargin: 36; width: paintedWidth; height: 30; // Text size - size: 22; + size: 18; // Style color: hifi.colors.baseGray; } @@ -334,6 +346,7 @@ Item { HiFiGlyphs { id: closeGlyphButton_connections; text: hifi.glyphs.close; + color: hifi.colors.lightGrayText; size: 26; anchors.top: parent.top; anchors.topMargin: 10; @@ -363,7 +376,7 @@ Item { height: 40; // Anchors anchors.left: parent.left; - anchors.leftMargin: 16; + anchors.leftMargin: 36; anchors.right: parent.right; anchors.rightMargin: 16; anchors.top: chooseRecipientText_connections.bottom; @@ -374,8 +387,9 @@ Item { colorScheme: hifi.colorSchemes.faintGray; hasClearButton: true; hasRoundedBorder: true; + roundedBorderRadius: filterBar.height/2; anchors.fill: parent; - placeholderText: "filter recipients"; + centerPlaceholderGlyph: hifi.glyphs.search; onTextChanged: { buildFilteredConnectionsModel(); @@ -461,17 +475,28 @@ Item { // Choose Recipient Nearby BEGIN Rectangle { id: chooseRecipientNearby; + z: 997; + color: "#80000000"; property string selectedRecipient; visible: root.currentActiveView === "chooseRecipientNearby"; anchors.fill: parent; - color: "#AAAAAA"; + + // This object is always used in a popup or full-screen Wallet section. + // This MouseArea is used to prevent a user from being + // able to click on a button/mouseArea underneath the popup/section. + MouseArea { + anchors.fill: parent; + propagateComposedEvents: false; + } Rectangle { anchors.centerIn: parent; width: parent.width - 30; height: parent.height - 30; + color: "#FFFFFF"; + radius: 8; RalewaySemiBold { text: "Choose Recipient:"; @@ -483,7 +508,7 @@ Item { width: paintedWidth; height: 30; // Text size - size: 22; + size: 18; // Style color: hifi.colors.baseGray; } @@ -491,6 +516,7 @@ Item { HiFiGlyphs { id: closeGlyphButton_nearby; text: hifi.glyphs.close; + color: hifi.colors.lightGrayText; size: 26; anchors.top: parent.top; anchors.topMargin: 10; @@ -676,9 +702,9 @@ Item { // Choose Recipient Nearby END // Send Money Screen BEGIN - Rectangle { + Item { id: sendMoneyStep; - z: 997; + z: 996; property string referrer; // either "connections" or "nearby" property string selectedRecipientNodeID; @@ -688,12 +714,12 @@ Item { visible: root.currentActiveView === "sendMoneyStep"; anchors.fill: parent; - color: "#AAAAAA"; Rectangle { anchors.centerIn: parent; width: parent.width - 30; height: parent.height - 30; + color: "#AAAAAA"; RalewaySemiBold { id: sendMoneyText_sendMoneyStep; @@ -806,7 +832,7 @@ Item { anchors.right: parent.right; height: 50; // Style - leftPlaceholderGlyph: hifi.glyphs.hfc; + leftPermanentGlyph: hifi.glyphs.hfc; activeFocusOnPress: true; activeFocusOnTab: true; @@ -1049,6 +1075,7 @@ Item { HiFiGlyphs { id: closeGlyphButton_paymentSuccess; text: hifi.glyphs.close; + color: lightGrayText; size: 26; anchors.top: parent.top; anchors.topMargin: 10; @@ -1234,6 +1261,7 @@ Item { HiFiGlyphs { id: closeGlyphButton_paymentFailure; text: hifi.glyphs.close; + color: hifi.colors.lightGrayText; size: 26; anchors.top: parent.top; anchors.topMargin: 10; diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 0826325a57..691f3cfdc6 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -591,10 +591,16 @@ getConnectionData(false); break; case 'enable_ChooseRecipientNearbyMode': - Script.update.connect(updateOverlays); + if (!isUpdateOverlaysWired) { + Script.update.connect(updateOverlays); + isUpdateOverlaysWired = true; + } break; case 'disable_ChooseRecipientNearbyMode': - Script.update.disconnect(updateOverlays); + if (isUpdateOverlaysWired) { + Script.update.disconnect(updateOverlays); + isUpdateOverlaysWired = false; + } removeOverlays(); break; default: @@ -675,14 +681,18 @@ } } var isWired = false; + var isUpdateOverlaysWired = false; function off() { if (isWired) { // It is not ok to disconnect these twice, hence guard. Users.usernameFromIDReply.disconnect(usernameFromIDReply); - Script.update.disconnect(updateOverlays); Controller.mousePressEvent.disconnect(handleMouseEvent); Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent); isWired = false; } + if (isUpdateOverlaysWired) { + Script.update.disconnect(updateOverlays); + isUpdateOverlaysWired = false; + } triggerMapping.disable(); // It's ok if we disable twice. triggerPressMapping.disable(); // see above removeOverlays(); From 6b5389a167166a61687403333e7c3bd651d70025 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 18 Jan 2018 17:37:26 -0800 Subject: [PATCH 16/33] go go go go go --- .../qml/hifi/commerce/wallet/Wallet.qml | 2 +- .../wallet/sendMoney/RecipientDisplay.qml | 6 +- .../commerce/wallet/sendMoney/SendMoney.qml | 539 +++++++++--------- .../wallet/sendMoney/images/connection.svg | 14 + .../wallet/sendMoney/images/loader.gif | Bin 0 -> 59412 bytes .../wallet/sendMoney/images/nearby.svg | 27 + 6 files changed, 320 insertions(+), 268 deletions(-) create mode 100644 interface/resources/qml/hifi/commerce/wallet/sendMoney/images/connection.svg create mode 100644 interface/resources/qml/hifi/commerce/wallet/sendMoney/images/loader.gif create mode 100644 interface/resources/qml/hifi/commerce/wallet/sendMoney/images/nearby.svg diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index da67569bc3..ae42b8e3e1 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -389,7 +389,7 @@ Rectangle { // Item { id: tabButtonsContainer; - visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange"; + visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange" && sendMoney.currentActiveView !== "sendMoneyStep"; property int numTabs: 5; // Size width: root.width; diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/RecipientDisplay.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/RecipientDisplay.qml index 267cf0ed51..1e7494583f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/RecipientDisplay.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/RecipientDisplay.qml @@ -46,7 +46,7 @@ Item { // Text size size: 18; // Style - color: hifi.colors.baseGray; + color: hifi.colors.white; verticalAlignment: Text.AlignBottom; elide: Text.ElideRight; } @@ -63,7 +63,7 @@ Item { // Text size size: 16; // Style - color: hifi.colors.baseGray; + color: hifi.colors.white; verticalAlignment: Text.AlignTop; elide: Text.ElideRight; } @@ -108,7 +108,7 @@ Item { // Text size size: 16; // Style - color: hifi.colors.baseGray; + color: hifi.colors.white; verticalAlignment: Text.AlignVCenter; elide: Text.ElideRight; } diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index 905fb548b2..2e88b91f5d 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -29,8 +29,9 @@ Item { property int parentAppNavBarHeight; property string currentActiveView: "sendMoneyHome"; property string nextActiveView: ""; - property bool isCurrentlyFullScreen: chooseRecipientConnection.visible || - chooseRecipientNearby.visible || sendMoneyStep.visible || paymentSuccess.visible || paymentFailure.visible; + property bool shouldShowTopAndBottomOfWallet: chooseRecipientConnection.visible || + chooseRecipientNearby.visible || paymentSuccess.visible || paymentFailure.visible; + property bool shouldShowTopOfWallet: sendMoneyStep.visible; property bool isCurrentlySendingMoney: false; // This object is always used in a popup or full-screen Wallet section. @@ -38,9 +39,9 @@ Item { // able to click on a button/mouseArea underneath the popup/section. MouseArea { x: 0; - y: root.isCurrentlyFullScreen ? 0 : root.parentAppTitleBarHeight; + y: (root.shouldShowTopAndBottomOfWallet && !root.shouldShowTopOfWallet) ? 0 : root.parentAppTitleBarHeight; width: parent.width; - height: root.isCurrentlyFullScreen ? parent.height : parent.height - root.parentAppTitleBarHeight - root.parentAppNavBarHeight; + height: (root.shouldShowTopAndBottomOfWallet || root.shouldShowTopOfWallet) ? parent.height : parent.height - root.parentAppTitleBarHeight - root.parentAppNavBarHeight; propagateComposedEvents: false; } @@ -195,6 +196,17 @@ Item { anchors.right: parent.right; anchors.bottom: parent.bottom; height: 440; + + + LinearGradient { + anchors.fill: parent; + start: Qt.point(0, 0); + end: Qt.point(0, height); + gradient: Gradient { + GradientStop { position: 0.0; color: hifi.colors.white } + GradientStop { position: 1.0; color: hifi.colors.faintGray } + } + } RalewaySemiBold { id: sendMoneyText; @@ -224,12 +236,13 @@ Item { Image { anchors.top: parent.top; - source: "../images/wallet-bg.jpg"; - height: 60; + source: "./images/connection.svg"; + height: 70; width: parent.width; fillMode: Image.PreserveAspectFit; horizontalAlignment: Image.AlignHCenter; verticalAlignment: Image.AlignTop; + mipmap: true; } RalewaySemiBold { @@ -265,12 +278,13 @@ Item { Image { anchors.top: parent.top; - source: "../images/wallet-bg.jpg"; - height: 60; + source: "./images/nearby.svg"; + height: 70; width: parent.width; fillMode: Image.PreserveAspectFit; horizontalAlignment: Image.AlignHCenter; verticalAlignment: Image.AlignTop; + mipmap: true; } RalewaySemiBold { @@ -714,284 +728,281 @@ Item { visible: root.currentActiveView === "sendMoneyStep"; anchors.fill: parent; + anchors.topMargin: root.parentAppTitleBarHeight; - Rectangle { - anchors.centerIn: parent; - width: parent.width - 30; - height: parent.height - 30; - color: "#AAAAAA"; + RalewaySemiBold { + id: sendMoneyText_sendMoneyStep; + text: "Send Money"; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 26; + anchors.left: parent.left; + anchors.leftMargin: 20; + width: paintedWidth; + height: 30; + // Text size + size: 22; + // Style + color: hifi.colors.white; + } + + Item { + id: sendToContainer; + anchors.top: sendMoneyText_sendMoneyStep.bottom; + anchors.topMargin: 20; + anchors.left: parent.left; + anchors.leftMargin: 20; + anchors.right: parent.right; + anchors.rightMargin: 20; + height: 80; RalewaySemiBold { - id: sendMoneyText_sendMoneyStep; - text: "Send Money To:"; + id: sendToText_sendMoneyStep; + text: "Send to:"; // Anchors anchors.top: parent.top; - anchors.topMargin: 26; anchors.left: parent.left; - anchors.leftMargin: 20; - width: paintedWidth; - height: 30; + anchors.bottom: parent.bottom; + width: 90; // Text size - size: 22; + size: 18; // Style - color: hifi.colors.baseGray; + color: hifi.colors.white; + verticalAlignment: Text.AlignVCenter; } - Item { - id: sendToContainer; - anchors.top: sendMoneyText_sendMoneyStep.bottom; - anchors.topMargin: 20; - anchors.left: parent.left; - anchors.leftMargin: 20; + RecipientDisplay { + anchors.top: parent.top; + anchors.left: sendToText_sendMoneyStep.right; + anchors.right: changeButton.left; + anchors.rightMargin: 12; + height: parent.height; + + displayName: sendMoneyStep.selectedRecipientDisplayName; + userName: sendMoneyStep.selectedRecipientUserName; + profilePic: sendMoneyStep.selectedRecipientProfilePic !== "" ? ((0 === sendMoneyStep.selectedRecipientProfilePic.indexOf("http")) ? + sendMoneyStep.selectedRecipientProfilePic : (Account.metaverseServerURL + sendMoneyStep.selectedRecipientProfilePic)) : ""; + isDisplayingNearby: sendMoneyStep.referrer === "nearby"; + } + + // "CHANGE" button + HifiControlsUit.Button { + id: changeButton; + color: hifi.buttons.none; + colorScheme: hifi.colorSchemes.white; anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - - RalewaySemiBold { - id: sendToText_sendMoneyStep; - text: "Send To:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: 90; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - RecipientDisplay { - anchors.top: parent.top; - anchors.left: sendToText_sendMoneyStep.right; - anchors.right: changeButton.left; - anchors.rightMargin: 12; - height: parent.height; - - displayName: sendMoneyStep.selectedRecipientDisplayName; - userName: sendMoneyStep.selectedRecipientUserName; - profilePic: sendMoneyStep.selectedRecipientProfilePic !== "" ? ((0 === sendMoneyStep.selectedRecipientProfilePic.indexOf("http")) ? - sendMoneyStep.selectedRecipientProfilePic : (Account.metaverseServerURL + sendMoneyStep.selectedRecipientProfilePic)) : ""; - isDisplayingNearby: sendMoneyStep.referrer === "nearby"; - } - - // "CHANGE" button - HifiControlsUit.Button { - id: changeButton; - color: hifi.buttons.black; - colorScheme: hifi.colorSchemes.dark; - anchors.right: parent.right; - anchors.verticalCenter: parent.verticalCenter; - height: 35; - width: 120; - text: "CHANGE"; - onClicked: { - if (sendMoneyStep.referrer === "connections") { - root.nextActiveView = "chooseRecipientConnection"; - } else if (sendMoneyStep.referrer === "nearby") { - root.nextActiveView = "chooseRecipientNearby"; - } - resetSendMoneyData(); + anchors.verticalCenter: parent.verticalCenter; + height: 35; + width: 100; + text: "CHANGE"; + onClicked: { + if (sendMoneyStep.referrer === "connections") { + root.nextActiveView = "chooseRecipientConnection"; + } else if (sendMoneyStep.referrer === "nearby") { + root.nextActiveView = "chooseRecipientNearby"; } + resetSendMoneyData(); + } + } + } + + Item { + id: amountContainer; + anchors.top: sendToContainer.bottom; + anchors.topMargin: 2; + anchors.left: parent.left; + anchors.leftMargin: 20; + anchors.right: parent.right; + anchors.rightMargin: 20; + height: 80; + + RalewaySemiBold { + id: amountText; + text: "Amount:"; + // Anchors + anchors.top: parent.top; + anchors.left: parent.left; + anchors.bottom: parent.bottom; + width: 90; + // Text size + size: 18; + // Style + color: hifi.colors.white; + verticalAlignment: Text.AlignVCenter; + } + + HifiControlsUit.TextField { + id: amountTextField; + colorScheme: hifi.colorSchemes.dark; + inputMethodHints: Qt.ImhDigitsOnly; + // Anchors + anchors.verticalCenter: parent.verticalCenter; + anchors.left: amountText.right; + anchors.right: parent.right; + height: 50; + // Style + leftPermanentGlyph: hifi.glyphs.hfc; + activeFocusOnPress: true; + activeFocusOnTab: true; + + validator: IntValidator { bottom: 0; } + + onAccepted: { + optionalMessage.focus = true; } } - Item { - id: amountContainer; - anchors.top: sendToContainer.bottom; + RalewaySemiBold { + id: amountTextFieldError; + // Anchors + anchors.top: amountTextField.bottom; anchors.topMargin: 2; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - - RalewaySemiBold { - id: amountText; - text: "Amount:"; - // Anchors - anchors.top: parent.top; - anchors.left: parent.left; - anchors.bottom: parent.bottom; - width: 90; - // Text size - size: 18; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignVCenter; - } - - HifiControlsUit.TextField { - id: amountTextField; - colorScheme: hifi.colorSchemes.light; - inputMethodHints: Qt.ImhDigitsOnly; - // Anchors - anchors.verticalCenter: parent.verticalCenter; - anchors.left: amountText.right; - anchors.right: parent.right; - height: 50; - // Style - leftPermanentGlyph: hifi.glyphs.hfc; - activeFocusOnPress: true; - activeFocusOnTab: true; - - validator: IntValidator { bottom: 0; } - - onAccepted: { - optionalMessage.focus = true; - } - } - - RalewaySemiBold { - id: amountTextFieldError; - // Anchors - anchors.top: amountTextField.bottom; - anchors.topMargin: 2; - anchors.left: amountTextField.left; - anchors.right: amountTextField.right; - height: 40; - // Text size - size: 16; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignTop; - horizontalAlignment: Text.AlignRight; - } + anchors.left: amountTextField.left; + anchors.right: amountTextField.right; + height: 40; + // Text size + size: 16; + // Style + color: hifi.colors.white; + verticalAlignment: Text.AlignTop; + horizontalAlignment: Text.AlignRight; } + } - Item { - id: messageContainer; - anchors.top: amountContainer.bottom; - anchors.topMargin: 16; - anchors.left: parent.left; - anchors.leftMargin: 20; - anchors.right: parent.right; - anchors.rightMargin: 20; - height: 140; + Item { + id: messageContainer; + anchors.top: amountContainer.bottom; + anchors.topMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 20; + anchors.right: parent.right; + anchors.rightMargin: 20; + height: 140; - FontLoader { id: firaSansSemiBold; source: "../../../../../fonts/FiraSans-SemiBold.ttf"; } - TextArea { - id: optionalMessage; - property int maximumLength: 70; - property string previousText: text; - placeholderText: "Optional Message"; - font.family: firaSansSemiBold.name; - font.pixelSize: 20; - // Anchors + FontLoader { id: firaSansSemiBold; source: "../../../../../fonts/FiraSans-SemiBold.ttf"; } + TextArea { + id: optionalMessage; + property int maximumLength: 72; + property string previousText: text; + placeholderText: "Optional Message (" + maximumLength + " character limit)"; + font.family: firaSansSemiBold.name; + font.pixelSize: 20; + // Anchors + anchors.fill: parent; + // Style + background: Rectangle { anchors.fill: parent; - // Style - background: Rectangle { - anchors.fill: parent; - color: optionalMessage.activeFocus ? hifi.colors.white : hifi.colors.textFieldLightBackground; - border.width: optionalMessage.activeFocus ? 1 : 0; - border.color: optionalMessage.activeFocus ? hifi.colors.primaryHighlight : hifi.colors.textFieldLightBackground; - } - color: hifi.colors.black; - textFormat: TextEdit.PlainText; - wrapMode: TextEdit.Wrap; - activeFocusOnPress: true; - activeFocusOnTab: true; - // Workaround for no max length on TextAreas - onTextChanged: { - if (text.length > maximumLength) { - var cursor = cursorPosition; - text = previousText; - if (cursor > text.length) { - cursorPosition = text.length; - } else { - cursorPosition = cursor-1; - } - } - previousText = text; - } + color: optionalMessage.activeFocus ? hifi.colors.black : hifi.colors.baseGrayShadow; + border.width: optionalMessage.activeFocus ? 1 : 0; + border.color: optionalMessage.activeFocus ? hifi.colors.primaryHighlight : hifi.colors.textFieldLightBackground; } - RalewaySemiBold { - id: optionalMessageCharacterCount; - text: optionalMessage.text.length + "/" + optionalMessage.maximumLength; - // Anchors - anchors.top: optionalMessage.bottom; - anchors.topMargin: 2; - anchors.right: optionalMessage.right; - height: paintedHeight; - // Text size - size: 16; - // Style - color: hifi.colors.baseGray; - verticalAlignment: Text.AlignTop; - horizontalAlignment: Text.AlignRight; + color: hifi.colors.white; + textFormat: TextEdit.PlainText; + wrapMode: TextEdit.Wrap; + activeFocusOnPress: true; + activeFocusOnTab: true; + // Workaround for no max length on TextAreas + onTextChanged: { + if (text.length > maximumLength) { + var cursor = cursorPosition; + text = previousText; + if (cursor > text.length) { + cursorPosition = text.length; + } else { + cursorPosition = cursor-1; + } + } + previousText = text; + } + } + RalewaySemiBold { + id: optionalMessageCharacterCount; + text: optionalMessage.text.length + "/" + optionalMessage.maximumLength; + // Anchors + anchors.top: optionalMessage.bottom; + anchors.topMargin: 4; + anchors.right: optionalMessage.right; + height: paintedHeight; + // Text size + size: 16; + // Style + color: optionalMessage.text.length === optionalMessage.maximumLength ? "#ea89a5" : hifi.colors.lightGrayText; + verticalAlignment: Text.AlignTop; + horizontalAlignment: Text.AlignRight; + } + } + + HifiControlsUit.CheckBox { + id: sendPubliclyCheckbox; + visible: true; // FIXME ONCE PARTICLE EFFECTS ARE IN + text: "Send Publicly" + // Anchors + anchors.top: messageContainer.bottom; + anchors.topMargin: 16; + anchors.left: parent.left; + anchors.leftMargin: 20; + anchors.right: parent.right; + anchors.rightMargin: 16; + boxSize: 24; + } + + Item { + id: bottomBarContainer; + anchors.left: parent.left; + anchors.leftMargin: 20; + anchors.right: parent.right; + anchors.rightMargin: 20; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 20; + height: 60; + + // "CANCEL" button + HifiControlsUit.Button { + id: cancelButton_sendMoneyStep; + color: hifi.buttons.noneBorderlessWhite; + colorScheme: hifi.colorSchemes.dark; + anchors.left: parent.left; + anchors.leftMargin: 24; + anchors.verticalCenter: parent.verticalCenter; + height: 40; + width: 150; + text: "CANCEL"; + onClicked: { + resetSendMoneyData(); + root.nextActiveView = "sendMoneyHome"; } } - Item { - id: bottomBarContainer; - anchors.top: messageContainer.bottom; - anchors.topMargin: 30; - anchors.left: parent.left; - anchors.leftMargin: 20; + // "SEND" button + HifiControlsUit.Button { + id: sendButton; + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.dark; anchors.right: parent.right; - anchors.rightMargin: 20; - height: 80; - - HifiControlsUit.CheckBox { - id: sendPubliclyCheckbox; - visible: false; // FIXME ONCE PARTICLE EFFECTS ARE IN - text: "Send Publicly" - // Anchors - anchors.verticalCenter: parent.verticalCenter; - anchors.left: parent.left; - anchors.right: cancelButton_sendMoneyStep.left; - anchors.rightMargin: 16; - boxSize: 24; - } - - // "CANCEL" button - HifiControlsUit.Button { - id: cancelButton_sendMoneyStep; - color: hifi.buttons.noneBorderless; - colorScheme: hifi.colorSchemes.dark; - anchors.right: sendButton.left; - anchors.rightMargin: 16; - anchors.verticalCenter: parent.verticalCenter; - height: 35; - width: 100; - text: "CANCEL"; - onClicked: { - resetSendMoneyData(); - root.nextActiveView = "sendMoneyHome"; - } - } - - // "SEND" button - HifiControlsUit.Button { - id: sendButton; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.right: parent.right; - anchors.verticalCenter: parent.verticalCenter; - height: 35; - width: 100; - text: "SEND"; - onClicked: { - if (parseInt(amountTextField.text) > parseInt(balanceText.text)) { - amountTextField.focus = true; - amountTextField.error = true; - amountTextFieldError.text = "amount exceeds available funds"; - } else if (amountTextField.text === "" || parseInt(amountTextField.text) < 1) { - amountTextField.focus = true; - amountTextField.error = true; - amountTextFieldError.text = "invalid amount"; - } else { - amountTextFieldError.text = ""; - amountTextField.error = false; - root.isCurrentlySendingMoney = true; - amountTextField.focus = false; - optionalMessage.focus = false; - if (sendMoneyStep.referrer === "connections") { - Commerce.transferHfcToUsername(sendMoneyStep.selectedRecipientUserName, parseInt(amountTextField.text), optionalMessage.text); - } else if (sendMoneyStep.referrer === "nearby") { - Commerce.transferHfcToNode(sendMoneyStep.selectedRecipientNodeID, parseInt(amountTextField.text), optionalMessage.text); - } + anchors.rightMargin: 24; + anchors.verticalCenter: parent.verticalCenter; + height: 40; + width: 150; + text: "SUBMIT"; + onClicked: { + if (parseInt(amountTextField.text) > parseInt(balanceText.text)) { + amountTextField.focus = true; + amountTextField.error = true; + amountTextFieldError.text = "amount exceeds available funds"; + } else if (amountTextField.text === "" || parseInt(amountTextField.text) < 1) { + amountTextField.focus = true; + amountTextField.error = true; + amountTextFieldError.text = "invalid amount"; + } else { + amountTextFieldError.text = ""; + amountTextField.error = false; + root.isCurrentlySendingMoney = true; + amountTextField.focus = false; + optionalMessage.focus = false; + if (sendMoneyStep.referrer === "connections") { + Commerce.transferHfcToUsername(sendMoneyStep.selectedRecipientUserName, parseInt(amountTextField.text), optionalMessage.text); + } else if (sendMoneyStep.referrer === "nearby") { + Commerce.transferHfcToNode(sendMoneyStep.selectedRecipientNodeID, parseInt(amountTextField.text), optionalMessage.text); } } } @@ -1157,7 +1168,7 @@ Item { // Text size size: 18; // Style - color: hifi.colors.baseGray; + color: hifi.colors.white; verticalAlignment: Text.AlignVCenter; } @@ -1172,7 +1183,7 @@ Item { anchors.verticalCenter: parent.verticalCenter; height: 50; // Style - color: hifi.colors.baseGray; + color: hifi.colors.lightGrayText; } RalewaySemiBold { @@ -1186,7 +1197,7 @@ Item { height: 50; // Style size: 22; - color: hifi.colors.baseGray; + color: hifi.colors.darkGray; } } diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/connection.svg b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/connection.svg new file mode 100644 index 0000000000..7c5403fda3 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/connection.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/loader.gif b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..0536bd1884f1cb4a814b729803b1996c8347d182 GIT binary patch literal 59412 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�)#8TsS*rVAU%J0tpt=B2=IG*djp3b$!Y|O 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 L8@}NiK8F7Q4CAa& literal 0 HcmV?d00001 diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/nearby.svg b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/nearby.svg new file mode 100644 index 0000000000..dec87e658d --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/nearby.svg @@ -0,0 +1,27 @@ + + + + + + + + + + From 3d3bfcf7a315a682972d741125007260c461af60 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 16 Jan 2018 12:35:03 -0800 Subject: [PATCH 17/33] check dirty flags when harvesting physics results --- libraries/entities/src/EntityItem.cpp | 47 +++++++++++++++++++++ libraries/entities/src/EntityItem.h | 8 ++++ libraries/physics/src/EntityMotionState.cpp | 33 ++++----------- libraries/shared/src/GLMHelpers.h | 1 + libraries/shared/src/SpatiallyNestable.cpp | 30 +++++++++++++ libraries/shared/src/SpatiallyNestable.h | 1 + 6 files changed, 95 insertions(+), 25 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index fe5213baa8..8ea1de7666 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1610,6 +1610,37 @@ void EntityItem::setPosition(const glm::vec3& value) { } } +void EntityItem::setWorldTransformAndVelocitiesUnlessDirtyFlags( + const glm::vec3& position, + const glm::quat& orientation, + const glm::vec3& linearVelocity, + const glm::vec3& angularVelocity) { + // only ever call this for harvesting results of physics simulation + // if a dirty bit is set then an update arrived (via script or network) overriding the physics simulation + uint32_t flags = _dirtyFlags & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES); + if (!flags) { + // flags are clear + setWorldTransform(position, orientation); + setWorldVelocity(linearVelocity); + setWorldAngularVelocity(angularVelocity); + setLastSimulated(usecTimestampNow()); + } else { + // only set properties NOT flagged + if (!(flags & Simulation::DIRTY_TRANSFORM)) { + setWorldTransform(position, orientation); + } + if (!(flags & Simulation::DIRTY_LINEAR_VELOCITY)) { + setWorldVelocity(linearVelocity); + } + if (!(flags & Simulation::DIRTY_ANGULAR_VELOCITY)) { + setWorldAngularVelocity(angularVelocity); + } + if (flags != (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES)) { + setLastSimulated(usecTimestampNow()); + } + } +} + void EntityItem::setParentID(const QUuid& value) { QUuid oldParentID = getParentID(); if (oldParentID != value) { @@ -1739,6 +1770,22 @@ void EntityItem::setVelocity(const glm::vec3& value) { } } +void EntityItem::zeroAllVelocitiesUnlessDirtyFlags() { + uint32_t flags = _dirtyFlags & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES); + if (!flags) { + setWorldVelocity(glm::vec3(0.0f)); + setWorldAngularVelocity(glm::vec3(0.0f)); + } else { + if (!(flags & Simulation::DIRTY_LINEAR_VELOCITY)) { + setWorldVelocity(glm::vec3(0.0f)); + } + if (!(flags & Simulation::DIRTY_ANGULAR_VELOCITY)) { + setWorldAngularVelocity(glm::vec3(0.0f)); + } + } + _acceleration = glm::vec3(0.0f); +} + void EntityItem::setDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); withWriteLock([&] { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ecfb7b5dcd..db2e7f7641 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -355,6 +355,7 @@ public: void setRotation(glm::quat orientation); void setVelocity(const glm::vec3& velocity); + void zeroAllVelocitiesUnlessDirtyFlags(); uint32_t getDirtyFlags() const; void markDirtyFlags(uint32_t mask); @@ -368,6 +369,13 @@ public: void* getPhysicsInfo() const { return _physicsInfo; } void setPhysicsInfo(void* data) { _physicsInfo = data; } + + void setWorldTransformAndVelocitiesUnlessDirtyFlags( + const glm::vec3& position, + const glm::quat& orientation, + const glm::vec3& linearVelocity, + const glm::vec3& angularVelocity); + EntityTreeElementPointer getElement() const { return _element; } EntityTreePointer getTree() const; virtual SpatialParentTree* getParentTree() const override; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 33ac887f4f..fe3e242a70 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -256,25 +256,12 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { assert(_entity); assert(entityTreeIsLocked()); measureBodyAcceleration(); - bool positionSuccess; - _entity->setWorldPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); - if (!positionSuccess) { - static QString repeatedMessage = - LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform " - "setPosition failed.*"); - qCDebug(physics) << "EntityMotionState::setWorldTransform setPosition failed" << _entity->getID(); - } - bool orientationSuccess; - _entity->setWorldOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); - if (!orientationSuccess) { - static QString repeatedMessage = - LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform " - "setOrientation failed.*"); - qCDebug(physics) << "EntityMotionState::setWorldTransform setOrientation failed" << _entity->getID(); - } - _entity->setVelocity(getBodyLinearVelocity()); - _entity->setAngularVelocity(getBodyAngularVelocity()); - _entity->setLastSimulated(usecTimestampNow()); + + _entity->setWorldTransformAndVelocitiesUnlessDirtyFlags( + bulletToGLM(worldTrans.getOrigin()), + bulletToGLM(worldTrans.getRotation()), + getBodyLinearVelocity(), + getBodyAngularVelocity()); if (_entity->getSimulatorID().isNull()) { _loopsWithoutOwner++; @@ -530,9 +517,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (!_body->isActive()) { // make sure all derivatives are zero - _entity->setVelocity(Vectors::ZERO); - _entity->setAngularVelocity(Vectors::ZERO); - _entity->setAcceleration(Vectors::ZERO); + _entity->zeroAllVelocitiesUnlessDirtyFlags(); _numInactiveUpdates++; } else { glm::vec3 gravity = _entity->getGravity(); @@ -559,9 +544,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (movingSlowly) { // velocities might not be zero, but we'll fake them as such, which will hopefully help convince // other simulating observers to deactivate their own copies - glm::vec3 zero(0.0f); - _entity->setVelocity(zero); - _entity->setAngularVelocity(zero); + _entity->zeroAllVelocitiesUnlessDirtyFlags(); } } _numInactiveUpdates = 0; diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 973998b927..4f761a4aac 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -253,6 +253,7 @@ glm::vec2 getFacingDir2D(const glm::mat4& m); inline bool isNaN(const glm::vec3& value) { return isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } inline bool isNaN(const glm::quat& value) { return isNaN(value.w) || isNaN(value.x) || isNaN(value.y) || isNaN(value.z); } +inline bool isNaN(const glm::mat3& value) { return isNaN(value * glm::vec3(1.0f)); } glm::mat4 orthoInverse(const glm::mat4& m); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 20a5a76b73..324cee3417 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -464,6 +464,36 @@ glm::vec3 SpatiallyNestable::localToWorldDimensions(const glm::vec3& dimensions, return dimensions; } +void SpatiallyNestable::setWorldTransform(const glm::vec3& position, const glm::quat& orientation) { + // guard against introducing NaN into the transform + if (isNaN(orientation) || isNaN(position)) { + return; + } + + bool changed = false; + bool success = true; + Transform parentTransform = getParentTransform(success); + _transformLock.withWriteLock([&] { + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + if (myWorldTransform.getRotation() != orientation) { + changed = true; + myWorldTransform.setRotation(orientation); + } + if (myWorldTransform.getTranslation() != position) { + changed = true; + myWorldTransform.setTranslation(position); + } + if (changed) { + Transform::inverseMult(_transform, parentTransform, myWorldTransform); + _translationChanged = usecTimestampNow(); + } + }); + if (success && changed) { + locationChanged(false); + } +} + glm::vec3 SpatiallyNestable::getWorldPosition(bool& success) const { return getTransform(success).getTranslation(); } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 2a315e9230..090ca4c266 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -87,6 +87,7 @@ public: virtual Transform getParentTransform(bool& success, int depth = 0) const; + void setWorldTransform(const glm::vec3& position, const glm::quat& orientation); virtual glm::vec3 getWorldPosition(bool& success) const; virtual glm::vec3 getWorldPosition() const; virtual void setWorldPosition(const glm::vec3& position, bool& success, bool tellPhysics = true); From 75b5635d2fbf9c0fad8ee4a041061deeefc284d3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Jan 2018 13:51:07 -0800 Subject: [PATCH 18/33] less word salad --- libraries/entities/src/EntityItem.cpp | 47 ------------------ libraries/entities/src/EntityItem.h | 7 --- libraries/physics/src/EntityMotionState.cpp | 53 ++++++++++++++++++--- libraries/physics/src/EntityMotionState.h | 1 + 4 files changed, 47 insertions(+), 61 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8ea1de7666..fe5213baa8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1610,37 +1610,6 @@ void EntityItem::setPosition(const glm::vec3& value) { } } -void EntityItem::setWorldTransformAndVelocitiesUnlessDirtyFlags( - const glm::vec3& position, - const glm::quat& orientation, - const glm::vec3& linearVelocity, - const glm::vec3& angularVelocity) { - // only ever call this for harvesting results of physics simulation - // if a dirty bit is set then an update arrived (via script or network) overriding the physics simulation - uint32_t flags = _dirtyFlags & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES); - if (!flags) { - // flags are clear - setWorldTransform(position, orientation); - setWorldVelocity(linearVelocity); - setWorldAngularVelocity(angularVelocity); - setLastSimulated(usecTimestampNow()); - } else { - // only set properties NOT flagged - if (!(flags & Simulation::DIRTY_TRANSFORM)) { - setWorldTransform(position, orientation); - } - if (!(flags & Simulation::DIRTY_LINEAR_VELOCITY)) { - setWorldVelocity(linearVelocity); - } - if (!(flags & Simulation::DIRTY_ANGULAR_VELOCITY)) { - setWorldAngularVelocity(angularVelocity); - } - if (flags != (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES)) { - setLastSimulated(usecTimestampNow()); - } - } -} - void EntityItem::setParentID(const QUuid& value) { QUuid oldParentID = getParentID(); if (oldParentID != value) { @@ -1770,22 +1739,6 @@ void EntityItem::setVelocity(const glm::vec3& value) { } } -void EntityItem::zeroAllVelocitiesUnlessDirtyFlags() { - uint32_t flags = _dirtyFlags & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES); - if (!flags) { - setWorldVelocity(glm::vec3(0.0f)); - setWorldAngularVelocity(glm::vec3(0.0f)); - } else { - if (!(flags & Simulation::DIRTY_LINEAR_VELOCITY)) { - setWorldVelocity(glm::vec3(0.0f)); - } - if (!(flags & Simulation::DIRTY_ANGULAR_VELOCITY)) { - setWorldAngularVelocity(glm::vec3(0.0f)); - } - } - _acceleration = glm::vec3(0.0f); -} - void EntityItem::setDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); withWriteLock([&] { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index db2e7f7641..f9559a375b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -355,7 +355,6 @@ public: void setRotation(glm::quat orientation); void setVelocity(const glm::vec3& velocity); - void zeroAllVelocitiesUnlessDirtyFlags(); uint32_t getDirtyFlags() const; void markDirtyFlags(uint32_t mask); @@ -370,12 +369,6 @@ public: void setPhysicsInfo(void* data) { _physicsInfo = data; } - void setWorldTransformAndVelocitiesUnlessDirtyFlags( - const glm::vec3& position, - const glm::quat& orientation, - const glm::vec3& linearVelocity, - const glm::vec3& angularVelocity); - EntityTreeElementPointer getElement() const { return _element; } EntityTreePointer getTree() const; virtual SpatialParentTree* getParentTree() const override; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index fe3e242a70..420da5a1e0 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -257,11 +257,31 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { assert(entityTreeIsLocked()); measureBodyAcceleration(); - _entity->setWorldTransformAndVelocitiesUnlessDirtyFlags( - bulletToGLM(worldTrans.getOrigin()), - bulletToGLM(worldTrans.getRotation()), - getBodyLinearVelocity(), - getBodyAngularVelocity()); + // If transform or velocities are flagged as dirty it means a network or scripted change + // occured between the beginning and end of the stepSimulation() and we DON'T want to apply + // these physics simulation results. + uint32_t flags = _entity->getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES); + if (!flags) { + // flags are clear + _entity->setWorldTransform(bulletToGLM(worldTrans.getOrigin()), bulletToGLM(worldTrans.getRotation())); + _entity->setWorldVelocity(getBodyLinearVelocity()); + _entity->setWorldAngularVelocity(getBodyAngularVelocity()); + _entity->setLastSimulated(usecTimestampNow()); + } else { + // only set properties NOT flagged + if (!(flags & Simulation::DIRTY_TRANSFORM)) { + _entity->setWorldTransform(bulletToGLM(worldTrans.getOrigin()), bulletToGLM(worldTrans.getRotation())); + } + if (!(flags & Simulation::DIRTY_LINEAR_VELOCITY)) { + _entity->setWorldVelocity(getBodyLinearVelocity()); + } + if (!(flags & Simulation::DIRTY_ANGULAR_VELOCITY)) { + _entity->setWorldAngularVelocity(getBodyAngularVelocity()); + } + if (flags != (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES)) { + _entity->setLastSimulated(usecTimestampNow()); + } + } if (_entity->getSimulatorID().isNull()) { _loopsWithoutOwner++; @@ -517,7 +537,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (!_body->isActive()) { // make sure all derivatives are zero - _entity->zeroAllVelocitiesUnlessDirtyFlags(); + zeroCleanObjectVelocities(); _numInactiveUpdates++; } else { glm::vec3 gravity = _entity->getGravity(); @@ -544,7 +564,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ if (movingSlowly) { // velocities might not be zero, but we'll fake them as such, which will hopefully help convince // other simulating observers to deactivate their own copies - _entity->zeroAllVelocitiesUnlessDirtyFlags(); + zeroCleanObjectVelocities(); } } _numInactiveUpdates = 0; @@ -801,3 +821,22 @@ bool EntityMotionState::shouldBeLocallyOwned() const { void EntityMotionState::upgradeOutgoingPriority(uint8_t priority) { _outgoingPriority = glm::max(_outgoingPriority, priority); } + +void EntityMotionState::zeroCleanObjectVelocities() const { + // If transform or velocities are flagged as dirty it means a network or scripted change + // occured between the beginning and end of the stepSimulation() and we DON'T want to apply + // these physics simulation results. + uint32_t flags = _entity->getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES); + if (!flags) { + _entity->setWorldVelocity(glm::vec3(0.0f)); + _entity->setWorldAngularVelocity(glm::vec3(0.0f)); + } else { + if (!(flags & Simulation::DIRTY_LINEAR_VELOCITY)) { + _entity->setWorldVelocity(glm::vec3(0.0f)); + } + if (!(flags & Simulation::DIRTY_ANGULAR_VELOCITY)) { + _entity->setWorldAngularVelocity(glm::vec3(0.0f)); + } + } + _entity->setAcceleration(glm::vec3(0.0f)); +} diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index ddfd7e1e4c..784273d600 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -87,6 +87,7 @@ public: protected: // changes _outgoingPriority only if priority is larger void upgradeOutgoingPriority(uint8_t priority); + void zeroCleanObjectVelocities() const; #ifdef WANT_DEBUG_ENTITY_TREE_LOCKS bool entityTreeIsLocked() const; From 495c4f56e2f791452cb46a2d7b1ea08c6182579d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 18 Jan 2018 17:47:43 -0800 Subject: [PATCH 19/33] Only small tweaks remaining? --- .../wallet/sendMoney/RecipientDisplay.qml | 7 ++-- .../commerce/wallet/sendMoney/SendMoney.qml | 34 ++++++++++--------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/RecipientDisplay.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/RecipientDisplay.qml index 1e7494583f..43636d47ca 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/RecipientDisplay.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/RecipientDisplay.qml @@ -29,6 +29,7 @@ Item { property string displayName; property string userName; property string profilePic; + property string textColor: hifi.colors.white; Item { visible: root.isDisplayingNearby; @@ -46,7 +47,7 @@ Item { // Text size size: 18; // Style - color: hifi.colors.white; + color: root.textColor; verticalAlignment: Text.AlignBottom; elide: Text.ElideRight; } @@ -63,7 +64,7 @@ Item { // Text size size: 16; // Style - color: hifi.colors.white; + color: root.textColor; verticalAlignment: Text.AlignTop; elide: Text.ElideRight; } @@ -108,7 +109,7 @@ Item { // Text size size: 16; // Style - color: hifi.colors.white; + color: root.textColor; verticalAlignment: Text.AlignVCenter; elide: Text.ElideRight; } diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index 2e88b91f5d..ed959333d7 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -262,6 +262,7 @@ Item { anchors.fill: parent; onClicked: { root.nextActiveView = "chooseRecipientConnection"; + filterBar.text = ""; } } } @@ -934,7 +935,7 @@ Item { HifiControlsUit.CheckBox { id: sendPubliclyCheckbox; - visible: true; // FIXME ONCE PARTICLE EFFECTS ARE IN + visible: false; // FIXME ONCE PARTICLE EFFECTS ARE IN text: "Send Publicly" // Anchors anchors.top: messageContainer.bottom; @@ -1018,7 +1019,7 @@ Item { visible: root.isCurrentlySendingMoney; anchors.fill: parent; - color: Qt.rgba(0.0, 0.0, 0.0, 0.5); + color: Qt.rgba(0.0, 0.0, 0.0, 0.8); // This object is always used in a popup or full-screen Wallet section. // This MouseArea is used to prevent a user from being @@ -1030,11 +1031,10 @@ Item { AnimatedImage { id: sendingMoneyImage; - source: "../../../../../icons/profilePicLoading.gif" - width: 160; + source: "./images/loader.gif" + width: 96; height: width; - anchors.top: parent.top; - anchors.topMargin: 185; + anchors.verticalCenter: parent.verticalCenter; anchors.horizontalCenter: parent.horizontalCenter; } @@ -1042,11 +1042,11 @@ Item { text: "Sending"; // Anchors anchors.top: sendingMoneyImage.bottom; - anchors.topMargin: 22; + anchors.topMargin: 4; anchors.horizontalCenter: parent.horizontalCenter; width: paintedWidth; // Text size - size: 24; + size: 26; // Style color: hifi.colors.white; verticalAlignment: Text.AlignVCenter; @@ -1055,17 +1055,17 @@ Item { // Sending Money Overlay END // Payment Success BEGIN - Rectangle { + Item { id: paymentSuccess; visible: root.currentActiveView === "paymentSuccess"; anchors.fill: parent; - color: "#AAAAAA"; Rectangle { anchors.centerIn: parent; width: parent.width - 30; height: parent.height - 30; + color: "#FFFFFF"; RalewaySemiBold { id: paymentSentText; @@ -1138,6 +1138,7 @@ Item { anchors.left: sendToText_paymentSuccess.right; anchors.right: parent.right; height: parent.height; + textColor: hifi.colors.blueAccent; displayName: sendMoneyStep.selectedRecipientDisplayName; userName: sendMoneyStep.selectedRecipientUserName; @@ -1168,7 +1169,7 @@ Item { // Text size size: 18; // Style - color: hifi.colors.white; + color: hifi.colors.baseGray; verticalAlignment: Text.AlignVCenter; } @@ -1183,7 +1184,7 @@ Item { anchors.verticalCenter: parent.verticalCenter; height: 50; // Style - color: hifi.colors.lightGrayText; + color: hifi.colors.blueAccent; } RalewaySemiBold { @@ -1197,7 +1198,7 @@ Item { height: 50; // Style size: 22; - color: hifi.colors.darkGray; + color: hifi.colors.blueAccent; } } @@ -1215,7 +1216,7 @@ Item { // Text size size: 22; // Style - color: hifi.colors.baseGray; + color: hifi.colors.blueAccent; wrapMode: Text.Wrap; verticalAlignment: Text.AlignTop; } @@ -1241,17 +1242,17 @@ Item { // Payment Success END // Payment Failure BEGIN - Rectangle { + Item { id: paymentFailure; visible: root.currentActiveView === "paymentFailure"; anchors.fill: parent; - color: "#AAAAAA"; Rectangle { anchors.centerIn: parent; width: parent.width - 30; height: parent.height - 30; + color: "#FFFFFF"; RalewaySemiBold { id: paymentFailureText; @@ -1342,6 +1343,7 @@ Item { anchors.left: sentToText_paymentFailure.right; anchors.right: parent.right; height: parent.height; + textColor: hifi.colors.baseGray; displayName: sendMoneyStep.selectedRecipientDisplayName; userName: sendMoneyStep.selectedRecipientUserName; From 67e816756cab36d3253e99e50ec9a2ee826f2ef7 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 19 Jan 2018 01:51:32 +0000 Subject: [PATCH 20/33] make gcc happy --- libraries/ui/src/DesktopPreviewProvider.cpp | 4 +++- libraries/ui/src/DesktopPreviewProvider.h | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/ui/src/DesktopPreviewProvider.cpp b/libraries/ui/src/DesktopPreviewProvider.cpp index 4ae70a1eb0..31aa7a22e2 100644 --- a/libraries/ui/src/DesktopPreviewProvider.cpp +++ b/libraries/ui/src/DesktopPreviewProvider.cpp @@ -7,6 +7,8 @@ DesktopPreviewProvider::DesktopPreviewProvider() { } +constexpr const char* DesktopPreviewProvider::imagePaths[]; + QSharedPointer DesktopPreviewProvider::getInstance() { static QSharedPointer instance = DependencyManager::get(); return instance; @@ -41,4 +43,4 @@ void DesktopPreviewProvider::setPreviewDisabledReason(const QString& reasonStrin QImage& DesktopPreviewProvider::loadPreviewImage(QImage& image, const QString& path) const { return image = QImage(path).mirrored().convertToFormat(QImage::Format_RGBA8888); -} \ No newline at end of file +} diff --git a/libraries/ui/src/DesktopPreviewProvider.h b/libraries/ui/src/DesktopPreviewProvider.h index 07d39a6cdf..449c3723e1 100644 --- a/libraries/ui/src/DesktopPreviewProvider.h +++ b/libraries/ui/src/DesktopPreviewProvider.h @@ -16,7 +16,7 @@ class DesktopPreviewProvider : public QObject, public Dependency { DesktopPreviewProvider(); DesktopPreviewProvider(const DesktopPreviewProvider& other) = delete; - constexpr static char* imagePaths[] = { + constexpr static const char* imagePaths[] = { "images/preview-disabled.png", // USER "images/preview-privacy.png", // SECURE_SCREEN "images/preview.png", // VSYNC @@ -44,4 +44,4 @@ private: PreviewDisabledReasons m_previewDisabledReason = { USER }; mutable QImage m_previewDisabled[3]; -}; \ No newline at end of file +}; From e0e6fc711bba14648fd54711cb5e408cf5a67816 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 19 Jan 2018 16:05:09 +1300 Subject: [PATCH 21/33] Replace Pointers API function setNonHoverItems() with setDoesHover() --- .../src/raypick/PointerScriptingInterface.cpp | 10 +-- .../src/raypick/PointerScriptingInterface.h | 16 ++-- libraries/pointers/src/Pointer.cpp | 21 +++-- libraries/pointers/src/Pointer.h | 7 +- libraries/pointers/src/PointerManager.cpp | 14 ++-- libraries/pointers/src/PointerManager.h | 2 +- .../controllers/controllerDispatcher.js | 76 +++++++++---------- .../controllerModules/webSurfaceLaserInput.js | 14 ++-- 8 files changed, 77 insertions(+), 83 deletions(-) diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 8e50b1d629..a334834979 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -24,10 +24,6 @@ void PointerScriptingInterface::setIncludeItems(unsigned int uid, const QScriptV DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } -void PointerScriptingInterface::setNonHoverItems(unsigned int uid, const QScriptValue& nonHoverItems) const { - DependencyManager::get()->setNonHoverItems(uid, qVectorQUuidFromScriptValue(nonHoverItems)); -} - unsigned int PointerScriptingInterface::createPointer(const PickQuery::PickType& type, const QVariant& properties) { // Interaction with managers should always happen on the main thread if (QThread::currentThread() != qApp->thread()) { @@ -179,4 +175,8 @@ QVariantMap PointerScriptingInterface::getPrevPickResult(unsigned int uid) const result = pickResult->toVariantMap(); } return result; -} \ No newline at end of file +} + +void PointerScriptingInterface::setDoesHover(unsigned int uid, bool hover) const { + DependencyManager::get()->setDoesHover(uid, hover); +} diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 4791fd802e..451c132769 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -191,14 +191,6 @@ public: */ Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const; - /**jsdoc - * Sets a list of Entity IDs, Overlay IDs, and/or Avatar IDs that the pointer should not send hover events to. - * @function Pointers.setNonHoverItems - * @param {number} uid - The ID of the Pointer, as returned by {@link Pointers.createPointer}. - * @param {Uuid[]} nonHoverItems - A list of IDs to that hover events should not be sent to. - */ - Q_INVOKABLE void setNonHoverItems(unsigned int uid, const QScriptValue& nonHoverItems) const; - /**jsdoc * Lock a Pointer onto a specific object (overlay, entity, or avatar). Optionally, provide an offset in object-space, otherwise the Pointer will lock on to the center of the object. * Not used by Stylus Pointers. @@ -210,6 +202,14 @@ public: */ Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay, offsetMat); } + /**jsdoc + * Sets whether or not a pointer should generate hover events. + * @function Pointers.setDoesHover + * @param {boolean} uid - The ID of the Pointer, as returned by {@link Pointers.createPointer}. + * @param {boolean} hover - If true then the pointer generates hover events, otherwise it does not. + */ + Q_INVOKABLE void setDoesHover(unsigned int uid, bool hove) const; + /**jsdoc * Check if a Pointer is associated with the left hand. * @function Pointers.isLeftHand diff --git a/libraries/pointers/src/Pointer.cpp b/libraries/pointers/src/Pointer.cpp index ead3c22687..0e542c47da 100644 --- a/libraries/pointers/src/Pointer.cpp +++ b/libraries/pointers/src/Pointer.cpp @@ -52,12 +52,6 @@ void Pointer::setIncludeItems(const QVector& includeItems) const { DependencyManager::get()->setIncludeItems(_pickUID, includeItems); } -void Pointer::setNonHoverItems(const QVector& nonHoverItems) { - withWriteLock([&] { - _nonHoverItems = nonHoverItems; - }); -} - bool Pointer::isLeftHand() const { return DependencyManager::get()->isLeftHand(_pickUID); } @@ -70,6 +64,12 @@ bool Pointer::isMouse() const { return DependencyManager::get()->isMouse(_pickUID); } +void Pointer::setDoesHover(bool doesHover) { + withWriteLock([&] { + _hover = doesHover; + }); +} + void Pointer::update(unsigned int pointerID) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { @@ -101,11 +101,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin } // Hover events - bool doHover = shouldHover(pickResult); - - auto pickResultMap = pickResult->toVariantMap(); - auto uuid = QUuid(pickResultMap.value("objectID", "").toString()); - doHover = doHover && !_nonHoverItems.contains(uuid); + bool doHover = _hover && shouldHover(pickResult); Pointer::PickedObject hoveredObject = getHoveredObject(pickResult); PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult); @@ -240,7 +236,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin } // if we disable the pointer or disable hovering, send hoverEnd events after triggerEnd - if (_hover && ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover))) { + if ((_hover || _prevHover) && ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover))) { if (_prevHoveredObject.type == ENTITY) { emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); } else if (_prevHoveredObject.type == OVERLAY) { @@ -253,6 +249,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin _prevHoveredObject = hoveredObject; _prevButtons = buttons; _prevEnabled = _enabled; + _prevHover = _hover; _prevDoHover = doHover; } diff --git a/libraries/pointers/src/Pointer.h b/libraries/pointers/src/Pointer.h index 6cb366e92a..ef0048cf1e 100644 --- a/libraries/pointers/src/Pointer.h +++ b/libraries/pointers/src/Pointer.h @@ -54,8 +54,6 @@ public: virtual void setIgnoreItems(const QVector& ignoreItems) const; virtual void setIncludeItems(const QVector& includeItems) const; - void setNonHoverItems(const QVector& nonHoverItems); - bool isLeftHand() const; bool isRightHand() const; bool isMouse() const; @@ -64,6 +62,8 @@ public: virtual void setLength(float length) {} virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) {} + void setDoesHover(bool hover); + void update(unsigned int pointerID); virtual void updateVisuals(const PickResultPointer& pickResult) = 0; void generatePointerEvents(unsigned int pointerID, const PickResultPointer& pickResult); @@ -99,12 +99,11 @@ private: PickedObject _prevHoveredObject; Buttons _prevButtons; bool _prevEnabled { false }; + bool _prevHover { false }; bool _prevDoHover { false }; std::unordered_map _triggeredObjects; PointerEvent::Button chooseButton(const std::string& button); - - QVector _nonHoverItems; }; #endif // hifi_Pick_h diff --git a/libraries/pointers/src/PointerManager.cpp b/libraries/pointers/src/PointerManager.cpp index f2953ce8c8..13b38457b6 100644 --- a/libraries/pointers/src/PointerManager.cpp +++ b/libraries/pointers/src/PointerManager.cpp @@ -108,13 +108,6 @@ void PointerManager::setIncludeItems(unsigned int uid, const QVector& inc } } -void PointerManager::setNonHoverItems(unsigned int uid, const QVector& nonHoverItems) const { - auto pointer = find(uid); - if (pointer) { - pointer->setNonHoverItems(nonHoverItems); - } -} - void PointerManager::setLength(unsigned int uid, float length) const { auto pointer = find(uid); if (pointer) { @@ -129,6 +122,13 @@ void PointerManager::setLockEndUUID(unsigned int uid, const QUuid& objectID, boo } } +void PointerManager::setDoesHover(unsigned int uid, bool hover) const { + auto pointer = find(uid); + if (pointer) { + pointer->setDoesHover(hover); + } +} + bool PointerManager::isLeftHand(unsigned int uid) { auto pointer = find(uid); if (pointer) { diff --git a/libraries/pointers/src/PointerManager.h b/libraries/pointers/src/PointerManager.h index a2a1e9dcd2..2c9a37e129 100644 --- a/libraries/pointers/src/PointerManager.h +++ b/libraries/pointers/src/PointerManager.h @@ -34,10 +34,10 @@ public: void setPrecisionPicking(unsigned int uid, bool precisionPicking) const; void setIgnoreItems(unsigned int uid, const QVector& ignoreEntities) const; void setIncludeItems(unsigned int uid, const QVector& includeEntities) const; - void setNonHoverItems(unsigned int uid, const QVector& nonHoverItems) const; void setLength(unsigned int uid, float length) const; void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) const; + void setDoesHover(unsigned int uid, bool hover) const; void update(); diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 15b025a7ea..fe18ed25f8 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -46,10 +46,10 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.tabletID = null; this.TABLET_UI_UUIDS = []; this.blacklist = []; - this.leftPointerNonHoverItem = null; - this.leftPointerNonHoverItemChanged = false; - this.rightPointerNonHoverItem = null; - this.rightPointerNonHoverItemChanged = false; + this.leftPointerDoesHover = true; + this.leftPointerDoesHoverChanged = false; + this.rightPointerDoesHover = true; + this.rightPointerDoesHoverChanged = false; this.pointerManager = new PointerManager(); // a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are @@ -163,26 +163,14 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } }; - this.setNonHoverItems = function () { - if (_this.leftPointerNonHoverItemChanged) { - if (_this.leftPointerNonHoverItem === null) { - Pointers.setNonHoverItems(_this.leftPointer, []); - } else if (_this.isTabletID(_this.leftPointerNonHoverItem)) { - Pointers.setNonHoverItems(_this.leftPointer, _this.TABLET_UI_UUIDS); - } else { - Pointers.setNonHoverItems(_this.leftPointer, [_this.leftPointerNonHoverItem]); - } - _this.leftPointerNonHoverItemChanged = false; + this.updateHovering = function () { + if (_this.leftPointerDoesHoverChanged) { + Pointers.setDoesHover(_this.leftPointer, _this.leftPointerDoesHover); + _this.leftPointerDoesHoverChanged = false; } - if (_this.rightPointerNonHoverItemChanged) { - if (_this.rightPointerNonHoverItem === null) { - Pointers.setNonHoverItems(_this.rightPointer, []); - } else if (_this.isTabletID(_this.rightPointerNonHoverItem)) { - Pointers.setNonHoverItems(_this.rightPointer, _this.TABLET_UI_UUIDS); - } else { - Pointers.setNonHoverItems(_this.rightPointer, [_this.rightPointerNonHoverItem]); - } - _this.rightPointerNonHoverItemChanged = false; + if (_this.rightPointerDoesHoverChanged) { + Pointers.setDoesHover(_this.rightPointer, _this.rightPointerDoesHover); + _this.rightPointerDoesHoverChanged = false; } }; @@ -358,15 +346,15 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); _this.markSlots(candidatePlugin, orderedPluginName); _this.pointerManager.makePointerVisible(candidatePlugin.parameters.handLaser); - if (candidatePlugin.parameters.handLaser.nonHoverItem !== undefined) { + if (candidatePlugin.parameters.handLaser.doesHover !== undefined) { if (candidatePlugin.parameters.handLaser.hand === LEFT_HAND - && _this.leftPointerNonHoverItem !== candidatePlugin.parameters.handLaser.nonHoverItem) { - _this.leftPointerNonHoverItem = candidatePlugin.parameters.handLaser.nonHoverItem; - _this.leftPointerNonHoverItemChanged = true; + && _this.leftPointerDoesHover !== candidatePlugin.parameters.handLaser.doesHover) { + _this.leftPointerDoesHover = candidatePlugin.parameters.handLaser.doesHover; + _this.leftPointerDoesHoverChanged = true; } else if (candidatePlugin.parameters.handLaser.hand === RIGHT_HAND - && _this.rightPointerNonHoverItem !== candidatePlugin.parameters.handLaser.nonHoverItem) { - _this.rightPointerNonHoverItem = candidatePlugin.parameters.handLaser.nonHoverItem; - _this.rightPointerNonHoverItemChanged = true; + && _this.rightPointerDoesHover !== candidatePlugin.parameters.handLaser.doesHover) { + _this.rightPointerDoesHover = candidatePlugin.parameters.handLaser.doesHover; + _this.rightPointerDoesHoverChanged = true; } } @@ -402,15 +390,15 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var runningness = plugin.run(controllerData, deltaTime); if (runningness.active) { - if (plugin.parameters.handLaser.nonHoverItem !== undefined) { + if (plugin.parameters.handLaser.doesHover !== undefined) { if (plugin.parameters.handLaser.hand === LEFT_HAND - && _this.leftPointerNonHoverItem !== plugin.parameters.handLaser.nonHoverItem) { - _this.leftPointerNonHoverItem = plugin.parameters.handLaser.nonHoverItem; - _this.leftPointerNonHoverItemChanged = true; + && _this.leftPointerDoesHover !== plugin.parameters.handLaser.doesHover) { + _this.leftPointerDoesHover = plugin.parameters.handLaser.doesHover; + _this.leftPointerDoesHoverChanged = true; } else if (plugin.parameters.handLaser.hand === RIGHT_HAND - && _this.rightPointerNonHoverItem !== plugin.parameters.handLaser.nonHoverItem) { - _this.rightPointerNonHoverItem = plugin.parameters.handLaser.nonHoverItem; - _this.rightPointerNonHoverItemChanged = true; + && _this.rightPointerDoesHover !== plugin.parameters.handLaser.doesHover) { + _this.rightPointerDoesHover = plugin.parameters.handLaser.doesHover; + _this.rightPointerDoesHoverChanged = true; } } } @@ -421,6 +409,17 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); delete _this.runningPluginNames[runningPluginName]; _this.markSlots(plugin, false); _this.pointerManager.makePointerInvisible(plugin.parameters.handLaser); + + if (plugin.parameters.handLaser.doesHover !== undefined) { + if (plugin.parameters.handLaser.hand === LEFT_HAND && !_this.leftPointerDoesHover) { + _this.leftPointerDoesHover = true; + _this.leftPointerDoesHoverChanged = true; + } else if (plugin.parameters.handLaser.hand === RIGHT_HAND && !_this.rightPointerDoesHover) { + _this.rightPointerDoesHover = true; + _this.rightPointerDoesHoverChanged = true; + } + } + if (DEBUG) { print("controllerDispatcher stopping " + runningPluginName); } @@ -433,8 +432,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } } _this.pointerManager.updatePointersRenderState(controllerData.triggerClicks, controllerData.triggerValues); - - _this.setNonHoverItems(); + _this.updateHovering(); if (PROFILE) { Script.endProfileRange("dispatch.run"); diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 5b9afa3a2a..282dd36d17 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -90,7 +90,7 @@ Script.include("/~/system/libraries/controllers.js"); this.hoverItem = null; this.isTabletID = function (uuid) { - return [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHightlightID].indexOf(uuid) !== -1; + return [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID, HMD.homeButtonHighlightID].indexOf(uuid) !== -1; }; this.isReady = function(controllerData) { @@ -105,19 +105,19 @@ Script.include("/~/system/libraries/controllers.js"); } if (pointingAt !== this.getOtherModule().hoverItem) { + this.parameters.handLaser.doesHover = true; this.hoverItem = pointingAt; - this.getOtherModule().parameters.handLaser.nonHoverItem = pointingAt; } else { + this.parameters.handLaser.doesHover = false; this.hoverItem = null; - this.getOtherModule().parameters.handLaser.nonHoverItem = null; } return makeRunningValues(true, [], []); } } + this.parameters.handLaser.doesHover = false; this.hoverItem = null; - this.getOtherModule().parameters.handLaser.nonHoverItem = null; return makeRunningValues(false, [], []); }; @@ -135,11 +135,11 @@ Script.include("/~/system/libraries/controllers.js"); } if (pointingAt !== this.getOtherModule().hoverItem || isTriggerPressed) { + this.parameters.handLaser.doesHover = true; this.hoverItem = pointingAt; - this.getOtherModule().parameters.handLaser.nonHoverItem = pointingAt; } else { + this.parameters.handLaser.doesHover = false; this.hoverItem = null; - this.getOtherModule().parameters.handLaser.nonHoverItem = null; } return makeRunningValues(true, [], []); @@ -147,8 +147,8 @@ Script.include("/~/system/libraries/controllers.js"); this.deleteContextOverlay(); this.running = false; + this.parameters.handLaser.doesHover = false; this.hoverItem = null; - this.getOtherModule().parameters.handLaser.nonHoverItem = null; return makeRunningValues(false, [], []); }; From 45bc6b8dabf371d25b6841901be446dae7d6c57f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 19 Jan 2018 16:41:23 +1300 Subject: [PATCH 22/33] Dominant hand gets the highlight if both start pointing simultaneously --- .../controllerModules/webSurfaceLaserInput.js | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 282dd36d17..cc8378af84 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -87,6 +87,23 @@ Script.include("/~/system/libraries/controllers.js"); return MyAvatar.getDominantHand() === "right" ? 1 : 0; }; + this.letOtherHandRunFirst = function (controllerData, pointingAt) { + // If both hands are ready to run, let the other hand run first if it is the dominant hand so that it gets the + // highlight. + var isOtherTriggerPressed = controllerData.triggerValues[this.otherHand] > TRIGGER_OFF_VALUE; + var isLetOtherHandRunFirst = !this.getOtherModule().running + && this.getDominantHand() === this.otherHand + && (this.parameters.handLaser.allwaysOn || isOtherTriggerPressed); + if (isLetOtherHandRunFirst) { + var otherHandPointingAt = controllerData.rayPicks[this.otherHand].objectID; + if (this.isTabletID(otherHandPointingAt)) { + otherHandPointingAt = HMD.tabletID; + } + isLetOtherHandRunFirst = pointingAt === otherHandPointingAt; + } + return isLetOtherHandRunFirst; + }; + this.hoverItem = null; this.isTabletID = function (uuid) { @@ -94,25 +111,28 @@ Script.include("/~/system/libraries/controllers.js"); }; this.isReady = function(controllerData) { - var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE - && controllerData.triggerValues[this.otherHand] <= TRIGGER_OFF_VALUE; if (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData)) { this.updateAllwaysOn(); + + var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE; if (this.parameters.handLaser.allwaysOn || isTriggerPressed) { var pointingAt = controllerData.rayPicks[this.hand].objectID; if (this.isTabletID(pointingAt)) { pointingAt = HMD.tabletID; } - if (pointingAt !== this.getOtherModule().hoverItem) { - this.parameters.handLaser.doesHover = true; - this.hoverItem = pointingAt; - } else { - this.parameters.handLaser.doesHover = false; - this.hoverItem = null; - } + if (!this.letOtherHandRunFirst(controllerData, pointingAt)) { - return makeRunningValues(true, [], []); + if (pointingAt !== this.getOtherModule().hoverItem) { + this.parameters.handLaser.doesHover = true; + this.hoverItem = pointingAt; + } else { + this.parameters.handLaser.doesHover = false; + this.hoverItem = null; + } + + return makeRunningValues(true, [], []); + } } } From 12c48a38f75a6be2db0a545bb4ae057438016edb Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Fri, 19 Jan 2018 13:58:35 +0100 Subject: [PATCH 23/33] Normalized diffuse & specular of directional, point and spot lights such as a light intensity of 1 gives a perpendicular diffuse lighting of the same color as the albedo for dielectric materials. --- libraries/render-utils/src/LightingModel.slh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index 7d08fdabaf..be8330f198 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -186,7 +186,7 @@ float specularDistribution(SurfaceData surface) { // Add geometric factors G1(n,l) and G1(n,v) float smithInvG1NdotL = evalSmithInvG1(surface.roughness4, surface.ndotl); denom *= surface.smithInvG1NdotV * smithInvG1NdotL; - // Don't divide by PI as it will be done later + // Don't divide by PI as this is part of the light normalization factor float power = surface.roughness4 / denom; return power; } @@ -202,12 +202,11 @@ vec4 evalPBRShading(float metallic, vec3 fresnel, SurfaceData surface) { vec3 specular = fresnelColor * power * angleAttenuation; float diffuse = (1.0 - metallic) * angleAttenuation * (1.0 - fresnelColor.x); - diffuse /= 3.1415926; - // Diffuse is divided by PI but specular isn't because an infinitesimal volume light source - // has a multiplier of PI, says Naty Hoffman. + // We don't divided by PI, as the "normalized" equations state we should, because we decide, as Naty Hoffman, that + // we wish to have a similar color as raw albedo on a perfectly diffuse surface perpendicularly lit + // by a white light of intensity 1. But this is an arbitrary normalization of what light intensity "means". // (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf // page 23 paragraph "Punctual light sources") - return vec4(specular, diffuse); } @@ -222,9 +221,9 @@ vec4 evalPBRShadingDielectric(SurfaceData surface, float fresnel) { vec3 specular = vec3(fresnelScalar) * power * angleAttenuation; float diffuse = angleAttenuation * (1.0 - fresnelScalar); - diffuse /= 3.1415926; - // Diffuse is divided by PI but specular isn't because an infinitesimal volume light source - // has a multiplier of PI, says Naty Hoffman. + // We don't divided by PI, as the "normalized" equations state we should, because we decide, as Naty Hoffman, that + // we wish to have a similar color as raw albedo on a perfectly diffuse surface perpendicularly lit + // by a white light of intensity 1. But this is an arbitrary normalization of what light intensity "means". // (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf // page 23 paragraph "Punctual light sources") return vec4(specular, diffuse); @@ -239,8 +238,9 @@ vec4 evalPBRShadingMetallic(SurfaceData surface, vec3 fresnel) { float power = specularDistribution(surface); vec3 specular = fresnelColor * power * angleAttenuation; - // Specular isn't divided by PI because an infinitesimal volume light source - // has a multiplier of PI, says Naty Hoffman. + // We don't divided by PI, as the "normalized" equations state we should, because we decide, as Naty Hoffman, that + // we wish to have a similar color as raw albedo on a perfectly diffuse surface perpendicularly lit + // by a white light of intensity 1. But this is an arbitrary normalization of what light intensity "means". // (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf // page 23 paragraph "Punctual light sources") return vec4(specular, 0.f); From 27ea74f5bf6af58298626fa0ab34b382f2acd127 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 19 Jan 2018 11:22:37 -0700 Subject: [PATCH 24/33] Fix sortOrder param on tablet buttons --- .../ui/src/ui/TabletScriptingInterface.cpp | 31 +++++++++++++++++-- .../ui/src/ui/TabletScriptingInterface.h | 1 + .../developer/tests/dynamics/dynamicsTests.js | 3 +- .../utilities/render/debugHighlight.js | 3 +- scripts/developer/utilities/render/lod.js | 3 +- scripts/developer/utilities/render/luci.js | 3 +- scripts/system/chat.js | 3 +- scripts/system/generalSettings.js | 3 +- scripts/system/goto.js | 3 +- scripts/system/run.js | 3 +- scripts/system/tablet-users.js | 3 +- .../marketplace/clap/clapApp.js | 3 +- .../skyboxChanger/skyboxchanger.js | 3 +- 13 files changed, 40 insertions(+), 25 deletions(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index c69ec1ce84..33ff9b06f7 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -31,6 +31,8 @@ const QString SYSTEM_TOOLBAR = "com.highfidelity.interface.toolbar.system"; const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; const QString TabletScriptingInterface::QML = "hifi/tablet/TabletRoot.qml"; +const QString BUTTON_SORT_ORDER_KEY = "sortOrder"; +const int DEFAULT_BUTTON_SORT_ORDER = 100; static QString getUsername() { QString username = "Unknown user"; @@ -74,11 +76,20 @@ QVariant TabletButtonListModel::data(const QModelIndex& index, int role) const { } TabletButtonProxy* TabletButtonListModel::addButton(const QVariant& properties) { - auto tabletButtonProxy = QSharedPointer(new TabletButtonProxy(properties.toMap())); + QVariantMap newTabletButtonProperties = properties.toMap(); + if (newTabletButtonProperties.find(BUTTON_SORT_ORDER_KEY) == newTabletButtonProperties.end()) { + newTabletButtonProperties[BUTTON_SORT_ORDER_KEY] = DEFAULT_BUTTON_SORT_ORDER; + } + int insertButtonUsingIndex = computeNewButtonIndex(newTabletButtonProperties); + auto newTabletButtonProxy = QSharedPointer(new TabletButtonProxy(newTabletButtonProperties)); beginResetModel(); - _buttons.push_back(tabletButtonProxy); + if (insertButtonUsingIndex < _buttons.size()) { + _buttons.insert(_buttons.begin() + insertButtonUsingIndex, newTabletButtonProxy); + } else { + _buttons.push_back(newTabletButtonProxy); + } endResetModel(); - return tabletButtonProxy.data(); + return newTabletButtonProxy.data(); } void TabletButtonListModel::removeButton(TabletButtonProxy* button) { @@ -92,6 +103,20 @@ void TabletButtonListModel::removeButton(TabletButtonProxy* button) { endResetModel(); } +int TabletButtonListModel::computeNewButtonIndex(const QVariantMap& newButtonProperties) { + int buttonCount = (int)_buttons.size(); + int newButtonSortOrder = newButtonProperties[BUTTON_SORT_ORDER_KEY].toInt(); + if (newButtonSortOrder == DEFAULT_BUTTON_SORT_ORDER) return buttonCount; + for (int i = 0; i < buttonCount; i++) { + QVariantMap tabletButtonProperties = _buttons[i]->getProperties(); + int tabletButtonSortOrder = tabletButtonProperties[BUTTON_SORT_ORDER_KEY].toInt(); + if (newButtonSortOrder <= tabletButtonSortOrder) { + return i; + } + } + return buttonCount; +} + TabletButtonsProxyModel::TabletButtonsProxyModel(QObject *parent) : QSortFilterProxyModel(parent) { } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index 56e3ae257b..34827117f0 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -115,6 +115,7 @@ protected: friend class TabletProxy; TabletButtonProxy* addButton(const QVariant& properties); void removeButton(TabletButtonProxy* button); + int computeNewButtonIndex(const QVariantMap& newButtonProperties); using List = std::list>; static QHash _roles; static Qt::ItemFlags _flags; diff --git a/scripts/developer/tests/dynamics/dynamicsTests.js b/scripts/developer/tests/dynamics/dynamicsTests.js index c0b001eab3..e9262c9308 100644 --- a/scripts/developer/tests/dynamics/dynamicsTests.js +++ b/scripts/developer/tests/dynamics/dynamicsTests.js @@ -22,8 +22,7 @@ var button = tablet.addButton({ icon: Script.resolvePath("dynamicsTests.svg"), - text: "Dynamics", - sortOrder: 15 + text: "Dynamics" }); diff --git a/scripts/developer/utilities/render/debugHighlight.js b/scripts/developer/utilities/render/debugHighlight.js index e70565cec2..c2173f6e2a 100644 --- a/scripts/developer/utilities/render/debugHighlight.js +++ b/scripts/developer/utilities/render/debugHighlight.js @@ -32,8 +32,7 @@ var button = tablet.addButton({ text: TABLET_BUTTON_NAME, icon: ICON_URL, - activeIcon: ACTIVE_ICON_URL, - sortOrder: 1 + activeIcon: ACTIVE_ICON_URL }); var hasEventBridge = false; diff --git a/scripts/developer/utilities/render/lod.js b/scripts/developer/utilities/render/lod.js index dc0b99edc2..307e509d39 100644 --- a/scripts/developer/utilities/render/lod.js +++ b/scripts/developer/utilities/render/lod.js @@ -30,8 +30,7 @@ var button = tablet.addButton({ text: TABLET_BUTTON_NAME, icon: ICON_URL, - activeIcon: ACTIVE_ICON_URL, - sortOrder: 1 + activeIcon: ACTIVE_ICON_URL }); var hasEventBridge = false; diff --git a/scripts/developer/utilities/render/luci.js b/scripts/developer/utilities/render/luci.js index 1e2ac1261f..6482c884ff 100644 --- a/scripts/developer/utilities/render/luci.js +++ b/scripts/developer/utilities/render/luci.js @@ -31,8 +31,7 @@ var button = tablet.addButton({ text: TABLET_BUTTON_NAME, icon: ICON_URL, - activeIcon: ACTIVE_ICON_URL, - sortOrder: 1 + activeIcon: ACTIVE_ICON_URL }); var hasEventBridge = false; diff --git a/scripts/system/chat.js b/scripts/system/chat.js index 0cb414e23c..b0a2e114a3 100644 --- a/scripts/system/chat.js +++ b/scripts/system/chat.js @@ -945,8 +945,7 @@ tabletButton = tablet.addButton({ icon: tabletButtonIcon, activeIcon: tabletButtonActiveIcon, - text: tabletButtonName, - sortOrder: 0 + text: tabletButtonName }); Messages.subscribe(channelName); diff --git a/scripts/system/generalSettings.js b/scripts/system/generalSettings.js index 082528ffc5..d3848da7d0 100644 --- a/scripts/system/generalSettings.js +++ b/scripts/system/generalSettings.js @@ -37,8 +37,7 @@ tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton({ icon: "icons/tablet-icons/goto-i.svg", - text: buttonName, - sortOrder: 8 + text: buttonName }); } diff --git a/scripts/system/goto.js b/scripts/system/goto.js index d364bf579e..5cc5bad844 100644 --- a/scripts/system/goto.js +++ b/scripts/system/goto.js @@ -41,8 +41,7 @@ if (Settings.getValue("HUDUIEnabled")) { button = tablet.addButton({ icon: "icons/tablet-icons/goto-i.svg", activeIcon: "icons/tablet-icons/goto-a.svg", - text: buttonName, - sortOrder: 8 + text: buttonName }); } diff --git a/scripts/system/run.js b/scripts/system/run.js index 054cca6d9c..c34271b18d 100644 --- a/scripts/system/run.js +++ b/scripts/system/run.js @@ -10,8 +10,7 @@ var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var button = tablet.addButton({ icon: Script.resolvePath("assets/images/run.svg"), - text: "RUN", - sortOrder: 15 + text: "RUN" }); function onClicked() { diff --git a/scripts/system/tablet-users.js b/scripts/system/tablet-users.js index 6f37cd55eb..6181173818 100644 --- a/scripts/system/tablet-users.js +++ b/scripts/system/tablet-users.js @@ -37,8 +37,7 @@ var button = tablet.addButton({ icon: "icons/tablet-icons/users-i.svg", activeIcon: "icons/tablet-icons/users-a.svg", - text: "USERS", - sortOrder: 11 + text: "USERS" }); var onUsersScreen = false; diff --git a/unpublishedScripts/marketplace/clap/clapApp.js b/unpublishedScripts/marketplace/clap/clapApp.js index b2d8ce55db..7118b3623c 100644 --- a/unpublishedScripts/marketplace/clap/clapApp.js +++ b/unpublishedScripts/marketplace/clap/clapApp.js @@ -31,8 +31,7 @@ var activeButton = tablet.addButton({ icon: whiteIcon, activeIcon: blackIcon, text: APP_NAME, - isActive: isActive, - sortOrder: 11 + isActive: isActive }); if (isActive) { diff --git a/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js b/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js index 7bc65722cd..0bd23552e4 100644 --- a/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js +++ b/unpublishedScripts/marketplace/skyboxChanger/skyboxchanger.js @@ -32,8 +32,7 @@ var button = tablet.addButton({ icon: ICONS.icon, activeIcon: ICONS.activeIcon, - text: TABLET_BUTTON_NAME, - sortOrder: 1 + text: TABLET_BUTTON_NAME }); var hasEventBridge = false; From 94e6a68d4197e84b80a0de1b9396d6a7b7bf749e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 20 Jan 2018 09:50:24 +1300 Subject: [PATCH 25/33] Code review --- libraries/pointers/src/Pointer.cpp | 4 +- libraries/pointers/src/Pointer.h | 2 +- .../controllers/controllerDispatcher.js | 55 ++++++------------- 3 files changed, 19 insertions(+), 42 deletions(-) diff --git a/libraries/pointers/src/Pointer.cpp b/libraries/pointers/src/Pointer.cpp index 0e542c47da..8691ab8823 100644 --- a/libraries/pointers/src/Pointer.cpp +++ b/libraries/pointers/src/Pointer.cpp @@ -111,7 +111,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin hoveredEvent.setMoveOnHoverLeave(moveOnHoverLeave); // if shouldHover && !_prevDoHover, only send hoverBegin - if (_enabled && _hover && doHover && !_prevDoHover) { + if (_enabled && doHover && !_prevDoHover) { if (hoveredObject.type == ENTITY) { emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); } else if (hoveredObject.type == OVERLAY) { @@ -119,7 +119,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin } else if (hoveredObject.type == HUD) { emit pointerManager->hoverBeginHUD(hoveredEvent); } - } else if (_enabled && _hover && doHover) { + } else if (_enabled && doHover) { if (hoveredObject.type == OVERLAY) { if (_prevHoveredObject.type == OVERLAY) { if (hoveredObject.objectID == _prevHoveredObject.objectID) { diff --git a/libraries/pointers/src/Pointer.h b/libraries/pointers/src/Pointer.h index ef0048cf1e..62683cb6e7 100644 --- a/libraries/pointers/src/Pointer.h +++ b/libraries/pointers/src/Pointer.h @@ -62,7 +62,7 @@ public: virtual void setLength(float length) {} virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay, const glm::mat4& offsetMat = glm::mat4()) {} - void setDoesHover(bool hover); + virtual void setDoesHover(bool hover); void update(unsigned int pointerID); virtual void updateVisuals(const PickResultPointer& pickResult) = 0; diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index fe18ed25f8..4946a6525e 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -163,6 +163,20 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } }; + this.updateDoesHover = function(handLaser) { + if (handLaser.doesHover !== undefined) { + if (handLaser.hand === LEFT_HAND + && _this.leftPointerDoesHover !== handLaser.doesHover) { + _this.leftPointerDoesHover = handLaser.doesHover; + _this.leftPointerDoesHoverChanged = true; + } else if (handLaser.hand === RIGHT_HAND + && _this.rightPointerDoesHover !== handLaser.doesHover) { + _this.rightPointerDoesHover = handLaser.doesHover; + _this.rightPointerDoesHoverChanged = true; + } + } + } + this.updateHovering = function () { if (_this.leftPointerDoesHoverChanged) { Pointers.setDoesHover(_this.leftPointer, _this.leftPointerDoesHover); @@ -345,19 +359,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); _this.runningPluginNames[orderedPluginName] = true; _this.markSlots(candidatePlugin, orderedPluginName); _this.pointerManager.makePointerVisible(candidatePlugin.parameters.handLaser); - - if (candidatePlugin.parameters.handLaser.doesHover !== undefined) { - if (candidatePlugin.parameters.handLaser.hand === LEFT_HAND - && _this.leftPointerDoesHover !== candidatePlugin.parameters.handLaser.doesHover) { - _this.leftPointerDoesHover = candidatePlugin.parameters.handLaser.doesHover; - _this.leftPointerDoesHoverChanged = true; - } else if (candidatePlugin.parameters.handLaser.hand === RIGHT_HAND - && _this.rightPointerDoesHover !== candidatePlugin.parameters.handLaser.doesHover) { - _this.rightPointerDoesHover = candidatePlugin.parameters.handLaser.doesHover; - _this.rightPointerDoesHoverChanged = true; - } - } - + _this.updateDoesHover(candidatePlugin.parameters.handLaser); if (DEBUG) { print("controllerDispatcher running " + orderedPluginName); } @@ -387,39 +389,14 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (PROFILE) { Script.beginProfileRange("dispatch.run." + runningPluginName); } + _this.updateDoesHover(plugin.parameters.handLaser); var runningness = plugin.run(controllerData, deltaTime); - - if (runningness.active) { - if (plugin.parameters.handLaser.doesHover !== undefined) { - if (plugin.parameters.handLaser.hand === LEFT_HAND - && _this.leftPointerDoesHover !== plugin.parameters.handLaser.doesHover) { - _this.leftPointerDoesHover = plugin.parameters.handLaser.doesHover; - _this.leftPointerDoesHoverChanged = true; - } else if (plugin.parameters.handLaser.hand === RIGHT_HAND - && _this.rightPointerDoesHover !== plugin.parameters.handLaser.doesHover) { - _this.rightPointerDoesHover = plugin.parameters.handLaser.doesHover; - _this.rightPointerDoesHoverChanged = true; - } - } - } - if (!runningness.active) { // plugin is finished running, for now. remove it from the list // of running plugins and mark its activity-slots as "not in use" delete _this.runningPluginNames[runningPluginName]; _this.markSlots(plugin, false); _this.pointerManager.makePointerInvisible(plugin.parameters.handLaser); - - if (plugin.parameters.handLaser.doesHover !== undefined) { - if (plugin.parameters.handLaser.hand === LEFT_HAND && !_this.leftPointerDoesHover) { - _this.leftPointerDoesHover = true; - _this.leftPointerDoesHoverChanged = true; - } else if (plugin.parameters.handLaser.hand === RIGHT_HAND && !_this.rightPointerDoesHover) { - _this.rightPointerDoesHover = true; - _this.rightPointerDoesHoverChanged = true; - } - } - if (DEBUG) { print("controllerDispatcher stopping " + runningPluginName); } From 24dcc8788cd671e99ff8ecdd05f2c4eb087d6ae8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 20 Jan 2018 10:07:23 +1300 Subject: [PATCH 26/33] Code review --- libraries/pointers/src/Pointer.cpp | 3 +-- libraries/pointers/src/Pointer.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/pointers/src/Pointer.cpp b/libraries/pointers/src/Pointer.cpp index 8691ab8823..287d5a3c97 100644 --- a/libraries/pointers/src/Pointer.cpp +++ b/libraries/pointers/src/Pointer.cpp @@ -236,7 +236,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin } // if we disable the pointer or disable hovering, send hoverEnd events after triggerEnd - if ((_hover || _prevHover) && ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover))) { + if ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover)) { if (_prevHoveredObject.type == ENTITY) { emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); } else if (_prevHoveredObject.type == OVERLAY) { @@ -249,7 +249,6 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin _prevHoveredObject = hoveredObject; _prevButtons = buttons; _prevEnabled = _enabled; - _prevHover = _hover; _prevDoHover = doHover; } diff --git a/libraries/pointers/src/Pointer.h b/libraries/pointers/src/Pointer.h index 62683cb6e7..9fd434fb15 100644 --- a/libraries/pointers/src/Pointer.h +++ b/libraries/pointers/src/Pointer.h @@ -99,7 +99,6 @@ private: PickedObject _prevHoveredObject; Buttons _prevButtons; bool _prevEnabled { false }; - bool _prevHover { false }; bool _prevDoHover { false }; std::unordered_map _triggeredObjects; From 7898aa2c4b0f6ef879b02ac285dc5afe3d0cecf8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 20 Jan 2018 10:32:42 +1300 Subject: [PATCH 27/33] Code review --- .../controllers/controllerDispatcher.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 4946a6525e..a8658933e7 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -163,15 +163,13 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } }; - this.updateDoesHover = function(handLaser) { + this.updateDoesHover = function(handLaser, doesHover) { if (handLaser.doesHover !== undefined) { - if (handLaser.hand === LEFT_HAND - && _this.leftPointerDoesHover !== handLaser.doesHover) { - _this.leftPointerDoesHover = handLaser.doesHover; + if (handLaser.hand === LEFT_HAND && _this.leftPointerDoesHover !== doesHover) { + _this.leftPointerDoesHover = doesHover; _this.leftPointerDoesHoverChanged = true; - } else if (handLaser.hand === RIGHT_HAND - && _this.rightPointerDoesHover !== handLaser.doesHover) { - _this.rightPointerDoesHover = handLaser.doesHover; + } else if (handLaser.hand === RIGHT_HAND && _this.rightPointerDoesHover !== doesHover) { + _this.rightPointerDoesHover = doesHover; _this.rightPointerDoesHoverChanged = true; } } @@ -359,7 +357,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); _this.runningPluginNames[orderedPluginName] = true; _this.markSlots(candidatePlugin, orderedPluginName); _this.pointerManager.makePointerVisible(candidatePlugin.parameters.handLaser); - _this.updateDoesHover(candidatePlugin.parameters.handLaser); + _this.updateDoesHover(candidatePlugin.parameters.handLaser, + candidatePlugin.parameters.handLaser.doesHover); if (DEBUG) { print("controllerDispatcher running " + orderedPluginName); } @@ -389,14 +388,16 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (PROFILE) { Script.beginProfileRange("dispatch.run." + runningPluginName); } - _this.updateDoesHover(plugin.parameters.handLaser); var runningness = plugin.run(controllerData, deltaTime); - if (!runningness.active) { + if (runningness.active) { + _this.updateDoesHover(plugin.parameters.handLaser, plugin.parameters.handLaser.doesHover); + } else { // plugin is finished running, for now. remove it from the list // of running plugins and mark its activity-slots as "not in use" delete _this.runningPluginNames[runningPluginName]; _this.markSlots(plugin, false); _this.pointerManager.makePointerInvisible(plugin.parameters.handLaser); + _this.updateDoesHover(plugin.parameters.handLaser, true); if (DEBUG) { print("controllerDispatcher stopping " + runningPluginName); } From 41f3b792b62af366b47c35049f8b72f531c4fdb0 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 19 Jan 2018 14:34:52 -0700 Subject: [PATCH 28/33] Fix warnings --- libraries/ui/src/ui/TabletScriptingInterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 33ff9b06f7..2b89045246 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -83,7 +83,8 @@ TabletButtonProxy* TabletButtonListModel::addButton(const QVariant& properties) int insertButtonUsingIndex = computeNewButtonIndex(newTabletButtonProperties); auto newTabletButtonProxy = QSharedPointer(new TabletButtonProxy(newTabletButtonProperties)); beginResetModel(); - if (insertButtonUsingIndex < _buttons.size()) { + int buttonCount = (int)_buttons.size(); + if (insertButtonUsingIndex < buttonCount) { _buttons.insert(_buttons.begin() + insertButtonUsingIndex, newTabletButtonProxy); } else { _buttons.push_back(newTabletButtonProxy); From 4d408a8df5c6a18b683f25e6234be505e7f53f53 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Jan 2018 14:49:28 -0800 Subject: [PATCH 29/33] Nearby UI --- .../commerce/wallet/sendMoney/SendMoney.qml | 219 ++++++++---------- .../sendMoney/images/p2p-nearby-selected.svg | 27 +++ .../images/p2p-nearby-unselected.svg | 30 +++ 3 files changed, 156 insertions(+), 120 deletions(-) create mode 100644 interface/resources/qml/hifi/commerce/wallet/sendMoney/images/p2p-nearby-selected.svg create mode 100644 interface/resources/qml/hifi/commerce/wallet/sendMoney/images/p2p-nearby-unselected.svg diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index ed959333d7..55fca14c24 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -553,163 +553,142 @@ Item { } } - Item { - id: selectionInstructionsContainer; - visible: chooseRecipientNearby.selectedRecipient === ""; - anchors.fill: parent; - - RalewaySemiBold { - id: selectionInstructions_deselected; - text: "Click/trigger on an avatar nearby to select them..."; - // Anchors - anchors.bottom: parent.bottom; - anchors.bottomMargin: 200; - anchors.left: parent.left; - anchors.leftMargin: 58; - anchors.right: parent.right; - anchors.rightMargin: anchors.leftMargin; - height: paintedHeight; - // Text size - size: 20; - // Style - color: hifi.colors.baseGray; - horizontalAlignment: Text.AlignHCenter; - wrapMode: Text.Wrap; - } + RalewaySemiBold { + id: selectionInstructions; + text: chooseRecipientNearby.selectedRecipient === "" ? "Trigger or click on\nsomeone nearby to select them" : + "Trigger or click on\nsomeone else to select again"; + // Anchors + anchors.top: parent.top; + anchors.topMargin: 100; + anchors.left: parent.left; + anchors.leftMargin: 20; + anchors.right: parent.right; + anchors.rightMargin: anchors.leftMargin; + height: paintedHeight; + // Text size + size: 20; + // Style + color: hifi.colors.baseGray; + horizontalAlignment: Text.AlignHCenter; + wrapMode: Text.Wrap; } - Item { + Image { + anchors.top: selectionInstructions.bottom; + anchors.topMargin: 20; + anchors.bottom: selectionMadeContainer.top; + anchors.bottomMargin: 30; + source: "./images/p2p-nearby-unselected.svg"; + width: parent.width; + fillMode: Image.PreserveAspectFit; + horizontalAlignment: Image.AlignHCenter; + verticalAlignment: Image.AlignVCenter; + mipmap: true; + } + + Rectangle { id: selectionMadeContainer; - visible: !selectionInstructionsContainer.visible; - anchors.fill: parent; + visible: chooseRecipientNearby.selectedRecipient !== ""; + anchors.bottom: parent.bottom; + anchors.left: parent.left; + anchors.right: parent.right; + height: 190; + color: "#F3F3F3"; + radius: 8; + + // Used to square off the top left and top right edges of this container + Rectangle { + color: "#F3F3F3"; + height: selectionMadeContainer.radius; + anchors.top: selectionMadeContainer.top; + anchors.left: selectionMadeContainer.left; + anchors.right: selectionMadeContainer.right; + } RalewaySemiBold { id: sendToText; - text: "Send To:"; + text: "Send to:"; // Anchors anchors.top: parent.top; - anchors.topMargin: 120; + anchors.topMargin: 36; anchors.left: parent.left; - anchors.leftMargin: 12; + anchors.leftMargin: 36; width: paintedWidth; height: paintedHeight; // Text size - size: 20; + size: 18; // Style color: hifi.colors.baseGray; } + Image { + id: selectedImage; + anchors.top: parent.top; + anchors.topMargin: 24; + anchors.bottom: parent.bottom; + anchors.bottomMargin: 32; + anchors.left: sendToText.right; + anchors.leftMargin: 4; + source: "./images/p2p-nearby-selected.svg"; + width: 50; + fillMode: Image.PreserveAspectFit; + horizontalAlignment: Image.AlignHCenter; + verticalAlignment: Image.AlignVCenter; + mipmap: true; + } + RalewaySemiBold { id: avatarDisplayName; text: '"' + AvatarList.getAvatar(chooseRecipientNearby.selectedRecipient).sessionDisplayName + '"'; // Anchors - anchors.top: sendToText.bottom; - anchors.topMargin: 60; - anchors.left: parent.left; - anchors.leftMargin: 30; + anchors.top: parent.top; + anchors.topMargin: 34; + anchors.left: selectedImage.right; + anchors.leftMargin: 10; anchors.right: parent.right; - anchors.rightMargin: 30; + anchors.rightMargin: 10; height: paintedHeight; // Text size - size: 22; + size: 20; // Style - horizontalAlignment: Text.AlignHCenter; - color: hifi.colors.baseGray; - } - - RalewaySemiBold { - id: avatarNodeID; - text: chooseRecipientNearby.selectedRecipient; - // Anchors - anchors.top: avatarDisplayName.bottom; - anchors.topMargin: 6; - anchors.left: parent.left; - anchors.leftMargin: 30; - anchors.right: parent.right; - anchors.rightMargin: 30; - height: paintedHeight; - // Text size - size: 14; - // Style - horizontalAlignment: Text.AlignHCenter; - color: hifi.colors.lightGrayText; + color: hifi.colors.blueAccent; } RalewaySemiBold { id: avatarUserName; text: sendMoneyStep.selectedRecipientUserName; // Anchors - anchors.top: avatarNodeID.bottom; - anchors.topMargin: 12; - anchors.left: parent.left; - anchors.leftMargin: 30; + anchors.top: avatarDisplayName.bottom; + anchors.topMargin: 16; + anchors.left: selectedImage.right; + anchors.leftMargin: 10; anchors.right: parent.right; - anchors.rightMargin: 30; + anchors.rightMargin: 10; height: paintedHeight; // Text size - size: 22; + size: 18; // Style - horizontalAlignment: Text.AlignHCenter; color: hifi.colors.baseGray; } - RalewaySemiBold { - id: selectionInstructions_selected; - text: "Click/trigger on another avatar nearby to select them...\n\nor press 'Next' to continue."; - // Anchors + // "CHOOSE" button + HifiControlsUit.Button { + id: chooseButton; + color: hifi.buttons.blue; + colorScheme: hifi.colorSchemes.dark; + anchors.horizontalCenter: parent.horizontalCenter; anchors.bottom: parent.bottom; - anchors.bottomMargin: 200; - anchors.left: parent.left; - anchors.leftMargin: 58; - anchors.right: parent.right; - anchors.rightMargin: anchors.leftMargin; - height: paintedHeight; - // Text size - size: 20; - // Style - color: hifi.colors.baseGray; - horizontalAlignment: Text.AlignHCenter; - wrapMode: Text.Wrap; - } - } + anchors.bottomMargin: 20; + height: 40; + width: 110; + text: "CHOOSE"; + onClicked: { + sendMoneyStep.referrer = "nearby"; + sendMoneyStep.selectedRecipientNodeID = chooseRecipientNearby.selectedRecipient; + chooseRecipientNearby.selectedRecipient = ""; - // "Cancel" button - HifiControlsUit.Button { - id: cancelButton; - color: hifi.buttons.noneBorderless; - colorScheme: hifi.colorSchemes.dark; - anchors.left: parent.left; - anchors.leftMargin: 60; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 80; - height: 50; - width: 120; - text: "Cancel"; - onClicked: { - root.nextActiveView = "sendMoneyHome"; - resetSendMoneyData(); - } - } - - // "Next" button - HifiControlsUit.Button { - id: nextButton; - enabled: chooseRecipientNearby.selectedRecipient !== ""; - color: hifi.buttons.blue; - colorScheme: hifi.colorSchemes.dark; - anchors.right: parent.right; - anchors.rightMargin: 60; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 80; - height: 50; - width: 120; - text: "Next"; - onClicked: { - sendMoneyStep.referrer = "nearby"; - sendMoneyStep.selectedRecipientNodeID = chooseRecipientNearby.selectedRecipient; - chooseRecipientNearby.selectedRecipient = ""; - - root.nextActiveView = "sendMoneyStep"; + root.nextActiveView = "sendMoneyStep"; + } } } } @@ -790,7 +769,7 @@ Item { HifiControlsUit.Button { id: changeButton; color: hifi.buttons.none; - colorScheme: hifi.colorSchemes.white; + colorScheme: hifi.colorSchemes.dark; anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; height: 35; @@ -1086,7 +1065,7 @@ Item { HiFiGlyphs { id: closeGlyphButton_paymentSuccess; text: hifi.glyphs.close; - color: lightGrayText; + color: hifi.colors.lightGrayText; size: 26; anchors.top: parent.top; anchors.topMargin: 10; diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/p2p-nearby-selected.svg b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/p2p-nearby-selected.svg new file mode 100644 index 0000000000..59635a99b1 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/p2p-nearby-selected.svg @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/p2p-nearby-unselected.svg b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/p2p-nearby-unselected.svg new file mode 100644 index 0000000000..bba07b9567 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/images/p2p-nearby-unselected.svg @@ -0,0 +1,30 @@ + + + + + + + + + From 89e403d438bc76741aae4f153073939a7824db27 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Jan 2018 15:39:57 -0800 Subject: [PATCH 30/33] Balance text in send money --- .../commerce/wallet/sendMoney/SendMoney.qml | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index 55fca14c24..c87ef13a63 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -832,6 +832,58 @@ Item { } } + FiraSansSemiBold { + visible: amountTextFieldError.text === ""; + text: "Balance: "; + // Anchors + anchors.top: amountTextField.bottom; + anchors.topMargin: 2; + anchors.left: amountTextField.left; + anchors.right: sendMoneyBalanceText_HFC.left; + width: paintedWidth; + height: 40; + // Text size + size: 16; + // Style + color: hifi.colors.lightGrayText; + verticalAlignment: Text.AlignTop; + horizontalAlignment: Text.AlignRight; + } + HiFiGlyphs { + id: sendMoneyBalanceText_HFC; + visible: amountTextFieldError.text === ""; + text: hifi.glyphs.hfc; + // Size + size: 16; + // Anchors + anchors.top: amountTextField.bottom; + anchors.topMargin: 2; + anchors.right: sendMoneyBalanceText.left; + width: paintedWidth; + height: 40; + // Style + color: hifi.colors.lightGrayText; + verticalAlignment: Text.AlignTop; + horizontalAlignment: Text.AlignRight; + } + FiraSansSemiBold { + id: sendMoneyBalanceText; + visible: amountTextFieldError.text === ""; + text: balanceText.text; + // Anchors + anchors.top: amountTextField.bottom; + anchors.topMargin: 2; + anchors.right: amountTextField.right; + width: paintedWidth; + height: 40; + // Text size + size: 16; + // Style + color: hifi.colors.lightGrayText; + verticalAlignment: Text.AlignTop; + horizontalAlignment: Text.AlignRight; + } + RalewaySemiBold { id: amountTextFieldError; // Anchors @@ -895,7 +947,7 @@ Item { previousText = text; } } - RalewaySemiBold { + FiraSansSemiBold { id: optionalMessageCharacterCount; text: optionalMessage.text.length + "/" + optionalMessage.maximumLength; // Anchors @@ -1166,7 +1218,7 @@ Item { color: hifi.colors.blueAccent; } - RalewaySemiBold { + FiraSansSemiBold { id: amountSentText; text: amountTextField.text; // Anchors @@ -1371,7 +1423,7 @@ Item { color: hifi.colors.baseGray; } - RalewaySemiBold { + FiraSansSemiBold { id: amountSentText_paymentFailure; text: amountTextField.text; // Anchors From f6062ebfccb5a3653844fd69d0b8afdf820524cb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Jan 2018 16:00:08 -0800 Subject: [PATCH 31/33] new icon and button layout --- .../icons/tablet-icons/EmoteAppIcon.svg | 21 ++++++++++++++++++ scripts/system/emote.js | 2 +- scripts/system/html/EmoteApp.html | 22 +++++++++---------- 3 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 interface/resources/icons/tablet-icons/EmoteAppIcon.svg diff --git a/interface/resources/icons/tablet-icons/EmoteAppIcon.svg b/interface/resources/icons/tablet-icons/EmoteAppIcon.svg new file mode 100644 index 0000000000..340f0fcd2f --- /dev/null +++ b/interface/resources/icons/tablet-icons/EmoteAppIcon.svg @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/scripts/system/emote.js b/scripts/system/emote.js index f1f739c126..139870fd63 100644 --- a/scripts/system/emote.js +++ b/scripts/system/emote.js @@ -43,7 +43,7 @@ var activeTimer = false; // used to cancel active timer if a user plays an amima var activeEmote = false; // to keep track of the currently playing emote button = tablet.addButton({ - //icon: "icons/tablet-icons/emote.svg", // TODO - we need graphics for this + icon: "icons/tablet-icons/EmoteAppIcon.svg", text: EMOTE_LABEL, sortOrder: EMOTE_APP_SORT_ORDER }); diff --git a/scripts/system/html/EmoteApp.html b/scripts/system/html/EmoteApp.html index 30ef3e17a1..0a423b9b6c 100644 --- a/scripts/system/html/EmoteApp.html +++ b/scripts/system/html/EmoteApp.html @@ -44,11 +44,11 @@ input[type=button] { font-family: 'Raleway'; font-weight: bold; - font-size: 13px; + font-size: 20px; text-transform: uppercase; vertical-align: top; - height: 28px; - min-width: 120px; + height: 105px; + min-width: 190px; padding: 0px 18px; margin-right: 6px; border-radius: 5px; @@ -98,14 +98,14 @@

Click an emotion to Emote:

-

-

-

-

-

-

-

-

+

+

+

+

+

+

+

+

From 1dde640a40bd2c2536df04c5a9e8d30436ae2fdc Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Jan 2018 16:06:01 -0800 Subject: [PATCH 32/33] -_- --- interface/resources/qml/controls-uit/TextField.qml | 2 +- .../resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index e2552c24d0..a21d1f8efd 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -24,7 +24,7 @@ TextField { property bool isSearchField: false property string label: "" property real controlHeight: height + (textFieldLabel.visible ? textFieldLabel.height + 1 : 0) - property bool hasDefocusedBorder: false; + property bool hasDefocusedBorder: true; property bool hasRoundedBorder: false property int roundedBorderRadius: 4 property bool error: false; diff --git a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml index c87ef13a63..f66781c919 100644 --- a/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml +++ b/interface/resources/qml/hifi/commerce/wallet/sendMoney/SendMoney.qml @@ -402,6 +402,7 @@ Item { colorScheme: hifi.colorSchemes.faintGray; hasClearButton: true; hasRoundedBorder: true; + hasDefocusedBorder: false; roundedBorderRadius: filterBar.height/2; anchors.fill: parent; centerPlaceholderGlyph: hifi.glyphs.search; From b0f21c6931b2213032a1d1cf087e33095599bd71 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Sat, 20 Jan 2018 07:09:16 -0700 Subject: [PATCH 33/33] sorter variable names --- .../ui/src/ui/TabletScriptingInterface.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 2b89045246..0bc9676a2b 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -76,21 +76,21 @@ QVariant TabletButtonListModel::data(const QModelIndex& index, int role) const { } TabletButtonProxy* TabletButtonListModel::addButton(const QVariant& properties) { - QVariantMap newTabletButtonProperties = properties.toMap(); - if (newTabletButtonProperties.find(BUTTON_SORT_ORDER_KEY) == newTabletButtonProperties.end()) { - newTabletButtonProperties[BUTTON_SORT_ORDER_KEY] = DEFAULT_BUTTON_SORT_ORDER; + QVariantMap newProperties = properties.toMap(); + if (newProperties.find(BUTTON_SORT_ORDER_KEY) == newProperties.end()) { + newProperties[BUTTON_SORT_ORDER_KEY] = DEFAULT_BUTTON_SORT_ORDER; } - int insertButtonUsingIndex = computeNewButtonIndex(newTabletButtonProperties); - auto newTabletButtonProxy = QSharedPointer(new TabletButtonProxy(newTabletButtonProperties)); + int index = computeNewButtonIndex(newProperties); + auto button = QSharedPointer(new TabletButtonProxy(newProperties)); beginResetModel(); - int buttonCount = (int)_buttons.size(); - if (insertButtonUsingIndex < buttonCount) { - _buttons.insert(_buttons.begin() + insertButtonUsingIndex, newTabletButtonProxy); + int numButtons = (int)_buttons.size(); + if (index < numButtons) { + _buttons.insert(_buttons.begin() + index, button); } else { - _buttons.push_back(newTabletButtonProxy); + _buttons.push_back(button); } endResetModel(); - return newTabletButtonProxy.data(); + return button.data(); } void TabletButtonListModel::removeButton(TabletButtonProxy* button) { @@ -105,17 +105,17 @@ void TabletButtonListModel::removeButton(TabletButtonProxy* button) { } int TabletButtonListModel::computeNewButtonIndex(const QVariantMap& newButtonProperties) { - int buttonCount = (int)_buttons.size(); + int numButtons = (int)_buttons.size(); int newButtonSortOrder = newButtonProperties[BUTTON_SORT_ORDER_KEY].toInt(); - if (newButtonSortOrder == DEFAULT_BUTTON_SORT_ORDER) return buttonCount; - for (int i = 0; i < buttonCount; i++) { + if (newButtonSortOrder == DEFAULT_BUTTON_SORT_ORDER) return numButtons; + for (int i = 0; i < numButtons; i++) { QVariantMap tabletButtonProperties = _buttons[i]->getProperties(); int tabletButtonSortOrder = tabletButtonProperties[BUTTON_SORT_ORDER_KEY].toInt(); if (newButtonSortOrder <= tabletButtonSortOrder) { return i; } } - return buttonCount; + return numButtons; } TabletButtonsProxyModel::TabletButtonsProxyModel(QObject *parent)