diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index 04f106d0f9..14a84311aa 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -40,12 +40,20 @@ Rectangle { Hifi.QmlCommerce { id: commerce; + onAccountResult: { + if (result.status === "success") { + commerce.getKeyFilePathIfExists(); + } else { + // unsure how to handle a failure here. We definitely cannot proceed. + } + } + onLoginStatusResult: { if (!isLoggedIn && root.activeView !== "needsLogIn") { root.activeView = "needsLogIn"; } else if (isLoggedIn) { root.activeView = "initialize"; - commerce.getKeyFilePathIfExists(); + commerce.account(); } } @@ -203,7 +211,7 @@ Rectangle { commerce.getLoginStatus(); } } - + HifiWallet.NeedsLogIn { id: needsLogIn; visible: root.activeView === "needsLogIn"; @@ -239,7 +247,7 @@ Rectangle { } } } - + // // "WALLET NOT SET UP" START // @@ -250,7 +258,7 @@ Rectangle { anchors.bottom: parent.bottom; anchors.left: parent.left; anchors.right: parent.right; - + RalewayRegular { id: notSetUpText; text: "Your wallet isn't set up.

Set up your Wallet (no credit card necessary) to claim your free HFC " + @@ -281,7 +289,7 @@ Rectangle { anchors.left: parent.left; anchors.bottom: parent.bottom; anchors.bottomMargin: 24; - + // "Cancel" button HifiControlsUit.Button { id: cancelButton; diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 383223a49c..697249f740 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -35,12 +35,20 @@ Rectangle { Hifi.QmlCommerce { id: commerce; + onAccountResult: { + if (result.status === "success") { + commerce.getKeyFilePathIfExists(); + } else { + // unsure how to handle a failure here. We definitely cannot proceed. + } + } + onLoginStatusResult: { if (!isLoggedIn && root.activeView !== "needsLogIn") { root.activeView = "needsLogIn"; } else if (isLoggedIn) { root.activeView = "initialize"; - commerce.getKeyFilePathIfExists(); + commerce.account(); } } @@ -174,7 +182,7 @@ Rectangle { commerce.getLoginStatus(); } } - + HifiWallet.NeedsLogIn { id: needsLogIn; visible: root.activeView === "needsLogIn"; @@ -210,7 +218,7 @@ Rectangle { } } } - + // // "WALLET NOT SET UP" START // @@ -221,7 +229,7 @@ Rectangle { anchors.bottom: parent.bottom; anchors.left: parent.left; anchors.right: parent.right; - + RalewayRegular { id: notSetUpText; text: "Your wallet isn't set up.

Set up your Wallet (no credit card necessary) to claim your free HFC " + @@ -252,7 +260,7 @@ Rectangle { anchors.left: parent.left; anchors.bottom: parent.bottom; anchors.bottomMargin: 24; - + // "Cancel" button HifiControlsUit.Button { id: cancelButton; @@ -309,7 +317,7 @@ Rectangle { anchors.topMargin: 8; anchors.bottom: actionButtonsContainer.top; anchors.bottomMargin: 8; - + // // FILTER BAR START // @@ -383,7 +391,7 @@ Rectangle { itemHref: root_file_url; anchors.topMargin: 12; anchors.bottomMargin: 12; - + Connections { onSendToPurchases: { if (msg.method === 'purchases_itemInfoClicked') { @@ -402,7 +410,7 @@ Rectangle { anchors.left: parent.left; anchors.bottom: parent.bottom; width: parent.width; - + // Explanitory text RalewayRegular { id: haventPurchasedYet; diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 2faa08064d..a0664f4f9b 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -31,6 +31,13 @@ #include #include +// I know, right? But per https://www.openssl.org/docs/faq.html +// this avoids OPENSSL_Uplink(00007FF847238000,08): no OPENSSL_Applink +// at runtime. +#ifdef Q_OS_WIN +#include +#endif + static const char* KEY_FILE = "hifikey"; static const char* IMAGE_FILE = "hifi_image"; // eventually this will live in keyfile diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 2e53917ef7..d03842d45a 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -640,7 +640,7 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) { _qmlContext->setBaseUrl(baseUrl); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function f) { +void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function onQmlLoadedCallback) { if (QThread::currentThread() != thread()) { qCWarning(uiLogging) << "Called load on a non-surface thread"; } @@ -660,28 +660,28 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); if (qmlComponent->isLoading()) { connect(qmlComponent, &QQmlComponent::statusChanged, this, - [this, qmlComponent, targetContext, f](QQmlComponent::Status) { - finishQmlLoad(qmlComponent, targetContext, f); + [this, qmlComponent, targetContext, onQmlLoadedCallback](QQmlComponent::Status) { + finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); }); return; } - finishQmlLoad(qmlComponent, targetContext, f); + finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); } -void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function f) { - load(qmlSource, true, f); +void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function onQmlLoadedCallback) { + load(qmlSource, true, onQmlLoadedCallback); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, std::function f) { - load(qmlSource, false, f); +void OffscreenQmlSurface::load(const QUrl& qmlSource, std::function onQmlLoadedCallback) { + load(qmlSource, false, onQmlLoadedCallback); } void OffscreenQmlSurface::clearCache() { _qmlContext->engine()->clearComponentCache(); } -void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function f) { +void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function onQmlLoadedCallback) { disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { @@ -691,7 +691,6 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext return; } - QObject* newObject = qmlComponent->beginCreate(qmlContext); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { @@ -705,7 +704,20 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext } qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership); - f(qmlContext, newObject); + + // All quick items should be focusable + QQuickItem* newItem = qobject_cast(newObject); + if (newItem) { + // Make sure we make items focusable (critical for + // supporting keyboard shortcuts) + newItem->setFlag(QQuickItem::ItemIsFocusScope, true); + } + + // Make sure we will call callback for this codepath + // Call this before qmlComponent->completeCreate() otherwise ghost window appears + if (newItem && _rootItem) { + onQmlLoadedCallback(qmlContext, newObject); + } QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); if (qmlContext != _qmlContext && eventBridge && eventBridge != this) { @@ -717,15 +729,6 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext qmlComponent->completeCreate(); qmlComponent->deleteLater(); - - // All quick items should be focusable - QQuickItem* newItem = qobject_cast(newObject); - if (newItem) { - // Make sure we make items focusable (critical for - // supporting keyboard shortcuts) - newItem->setFlag(QQuickItem::ItemIsFocusScope, true); - } - // If we already have a root, just set a couple of flags and the ancestry if (newItem && _rootItem) { // Allow child windows to be destroyed from JS @@ -748,6 +751,8 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext _rootItem = newItem; _rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setSize(_quickWindow->renderTargetSize()); + // Call this callback after rootitem is set, otherwise VrMenu wont work + onQmlLoadedCallback(qmlContext, newObject); } void OffscreenQmlSurface::updateQuick() { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 7da929723c..95dabdef0f 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -50,11 +50,11 @@ public: void resize(const QSize& size, bool forceResize = false); QSize size() const; - Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, std::function f = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void load(const QUrl& qmlSource, std::function f = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void load(const QString& qmlSourceFile, std::function f = [](QQmlContext*, QObject*) {}) { - return load(QUrl(qmlSourceFile), f); + Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); + Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); + Q_INVOKABLE void load(const QUrl& qmlSource, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); + Q_INVOKABLE void load(const QString& qmlSourceFile, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}) { + return load(QUrl(qmlSourceFile), onQmlLoadedCallback); } void clearCache(); void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; } @@ -120,7 +120,7 @@ protected: private: static QOpenGLContext* getSharedContext(); - void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function f); + void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function onQmlLoadedCallback); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); void setupFbo(); bool allowNewFrame(uint8_t fps); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 3355901e6e..9a6f39c490 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -439,6 +439,7 @@ Script.include("/~/system/libraries/controllers.js"); // gather up the readiness of the near-grab modules var nearGrabNames = [ + this.hand === RIGHT_HAND ? "RightScaleAvatar" : "LeftScaleAvatar", this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index cf82de1820..916487277a 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -209,6 +209,15 @@ Script.include("/~/system/libraries/utils.js"); return this.exitModule(); } } + + var teleport = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightTeleporter" : "LeftTeleporter"); + if (teleport) { + var teleportReady = teleport.isReady(controllerData); + if (teleportReady.active) { + return this.exitModule(); + } + } + this.processControllerTriggers(controllerData); this.updateLaserPointer(controllerData); this.sendPickData(controllerData); @@ -251,4 +260,6 @@ Script.include("/~/system/libraries/utils.js"); disableDispatcherModule("LeftHandInEditMode"); disableDispatcherModule("RightHandInEditMode"); }; + + Script.scriptEnding.connect(this.cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/scaleAvatar.js b/scripts/system/controllers/controllerModules/scaleAvatar.js new file mode 100644 index 0000000000..2c85b75ea9 --- /dev/null +++ b/scripts/system/controllers/controllerModules/scaleAvatar.js @@ -0,0 +1,84 @@ +// handControllerGrab.js +// +// Created by Dante Ruiz on 9/11/17 +// +// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +/* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, + Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset, + setGrabCommunications, Menu, HMD, isInEditMode, AvatarList */ +/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ + +//Script.include("/~/system/libraries/controllerDispatcherUtils.js"); +(function () { + var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); + + function ScaleAvatar(hand) { + this.hand = hand; + this.scalingStartAvatarScale = 0; + this.scalingStartDistance = 0; + + this.parameters = dispatcherUtils.makeDispatcherModuleParameters( + 120, + this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], + [], + 100 + ); + + this.otherHand = function() { + return this.hand === dispatcherUtils.RIGHT_HAND ? dispatcherUtils.LEFT_HAND : dispatcherUtils.RIGHT_HAND; + }; + + this.getOtherModule = function() { + var otherModule = this.hand === dispatcherUtils.RIGHT_HAND ? leftScaleAvatar : rightScaleAvatar; + return otherModule; + }; + + this.triggersPressed = function(controllerData) { + if (controllerData.triggerValues[this.hand] === 1 && controllerData.secondaryValues[this.hand] === 1) { + return true; + } + return false; + }; + + this.isReady = function(controllerData) { + var otherModule = this.getOtherModule(); + if (this.triggersPressed(controllerData) && otherModule.triggersPressed(controllerData)) { + this.scalingStartAvatarScale = MyAvatar.scale; + this.scalingStartDistance = Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, + controllerData.controllerLocations[this.otherHand()].position)); + return dispatcherUtils.makeRunningValues(true, [], []); + } + return dispatcherUtils.makeRunningValues(false, [], []); + }; + + this.run = function(controllerData) { + var otherModule = this.getOtherModule(); + if (this.triggersPressed(controllerData) && otherModule.triggersPressed(controllerData)) { + if (this.hand === dispatcherUtils.RIGHT_HAND) { + var scalingCurrentDistance = Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, + controllerData.controllerLocations[this.otherHand()].position)); + + var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale; + MyAvatar.scale = newAvatarScale; + } + return dispatcherUtils.makeRunningValues(true, [], []); + } + return dispatcherUtils.makeRunningValues(false, [], []); + }; + } + + var leftScaleAvatar = new ScaleAvatar(dispatcherUtils.LEFT_HAND); + var rightScaleAvatar = new ScaleAvatar(dispatcherUtils.RIGHT_HAND); + + dispatcherUtils.enableDispatcherModule("LeftScaleAvatar", leftScaleAvatar); + dispatcherUtils.enableDispatcherModule("RightScaleAvatar", rightScaleAvatar); + + this.cleanup = function() { + dispatcherUtils.disableDispatcherModule("LeftScaleAvatar"); + dispatcherUtils.disableDispatcherModule("RightScaleAvatar"); + }; +})(); diff --git a/scripts/system/controllers/controllerModules/tabletStylusInput.js b/scripts/system/controllers/controllerModules/tabletStylusInput.js index 8a1262bac0..0d4f4ff78a 100644 --- a/scripts/system/controllers/controllerModules/tabletStylusInput.js +++ b/scripts/system/controllers/controllerModules/tabletStylusInput.js @@ -20,7 +20,7 @@ Script.include("/~/system/libraries/controllers.js"); var HAPTIC_STYLUS_STRENGTH = 1.0; var HAPTIC_STYLUS_DURATION = 20.0; - var WEB_DISPLAY_STYLUS_DISTANCE = 0.1; + var WEB_DISPLAY_STYLUS_DISTANCE = 0.5; var WEB_STYLUS_LENGTH = 0.2; var WEB_TOUCH_Y_OFFSET = 0.05; // how far forward (or back with a negative number) to slide stylus in hand @@ -474,7 +474,7 @@ Script.include("/~/system/libraries/controllers.js"); this.processStylus = function(controllerData) { this.updateStylusTip(); - if (!this.stylusTip.valid) { + if (!this.stylusTip.valid || this.overlayLaserActive(controllerData)) { this.pointFinger(false); this.hideStylus(); return false; @@ -646,6 +646,14 @@ Script.include("/~/system/libraries/controllers.js"); } }; + this.overlayLaserActive = function(controllerData) { + var overlayLaserModule = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightOverlayLaserInput" : "LeftOverlayLaserInput"); + if (overlayLaserModule) { + return overlayLaserModule.isReady(controllerData).active; + } + return false; + }; + this.isReady = function (controllerData) { if (this.processStylus(controllerData)) { return makeRunningValues(true, [], []); diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index fcf5ea0ed2..9bb3bcb2f9 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -170,6 +170,11 @@ function Teleporter(hand) { this.currentTarget = TARGET.INVALID; this.currentResult = null; + this.getOtherModule = function() { + var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; + return otherModule; + }; + this.teleportRayHandVisible = LaserPointers.createLaserPointer({ joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand", filter: RayPick.PICK_ENTITIES, @@ -231,15 +236,32 @@ function Teleporter(hand) { [], 100); + this.enterTeleport = function() { + if (coolInTimeout !== null) { + Script.clearTimeout(coolInTimeout); + } + + this.state = TELEPORTER_STATES.COOL_IN; + coolInTimeout = Script.setTimeout(function() { + if (_this.state === TELEPORTER_STATES.COOL_IN) { + _this.state = TELEPORTER_STATES.TARGETTING; + } + }, COOL_IN_DURATION); + }; + + this.isReady = function(controllerData, deltaTime) { - if (_this.buttonValue !== 0) { + var otherModule = this.getOtherModule(); + if (_this.buttonValue !== 0 && !otherModule.active) { + this.active = true; + this.enterTeleport(); return makeRunningValues(true, [], []); } return makeRunningValues(false, [], []); }; this.run = function(controllerData, deltaTime) { - _this.state = TELEPORTER_STATES.TARGETTING; + //_this.state = TELEPORTER_STATES.TARGETTING; // Get current hand pose information to see if the pose is valid var pose = Controller.getPoseValue(handInfo[(_this.hand === RIGHT_HAND) ? 'right' : 'left'].controllerInput); @@ -306,7 +328,7 @@ function Teleporter(hand) { return makeRunningValues(true, [], []); } - if (target === TARGET.NONE || target === TARGET.INVALID) { + if (target === TARGET.NONE || target === TARGET.INVALID || this.state === TELEPORTER_STATES.COOL_IN) { // Do nothing } else if (target === TARGET.SEAT) { Entities.callEntityMethod(result.objectID, 'sit'); @@ -319,6 +341,7 @@ function Teleporter(hand) { } this.disableLasers(); + this.active = false; return makeRunningValues(false, [], []); }; diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index e3375a5a27..3fcc158893 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -28,7 +28,8 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/inEditMode.js", "controllerModules/disableOtherModule.js", "controllerModules/farTrigger.js", - "controllerModules/teleport.js" + "controllerModules/teleport.js", + "controllerModules/scaleAvatar.js" ]; var DEBUG_MENU_ITEM = "Debug defaultScripts.js"; diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 773f79754d..bc2aa1a9c8 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -301,3 +301,14 @@ findGroupParent = function (controllerData, targetProps) { return targetProps; }; + +if (typeof module !== 'undefined') { + module.exports = { + makeDispatcherModuleParameters: makeDispatcherModuleParameters, + enableDispatcherModule: enableDispatcherModule, + disableDispatcherModule: disableDispatcherModule, + makeRunningValues: makeRunningValues, + LEFT_HAND: LEFT_HAND, + RIGHT_HAND: RIGHT_HAND + }; +}