Merge branch 'master' into flickable_web_pages

This commit is contained in:
vladest 2017-09-05 22:14:52 +02:00
commit dd6d530853
61 changed files with 1373 additions and 740 deletions

View file

@ -35,7 +35,7 @@ void ScriptableAvatar::startAnimation(const QString& url, float fps, float prior
return; return;
} }
_animation = DependencyManager::get<AnimationCache>()->getAnimation(url); _animation = DependencyManager::get<AnimationCache>()->getAnimation(url);
_animationDetails = AnimationDetails("", QUrl(url), fps, 0, loop, hold, false, firstFrame, lastFrame, true, firstFrame); _animationDetails = AnimationDetails("", QUrl(url), fps, 0, loop, hold, false, firstFrame, lastFrame, true, firstFrame, false);
_maskedJoints = maskedJoints; _maskedJoints = maskedJoints;
} }

View file

@ -6,7 +6,14 @@
<title>Welcome to Interface</title> <title>Welcome to Interface</title>
<style> <style>
body { @font-face {
font-family: 'Raleway Light';
src: url('../fonts/Raleway-Light.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
body {
background: black; background: black;
width: 100%; width: 100%;
overflow-x: hidden; overflow-x: hidden;
@ -15,6 +22,14 @@
padding: 0; padding: 0;
} }
a:link {color:inherit}
a:active {color:inherit}
a:visited {color:inherit}
a:hover {
color:inherit;
cursor: pointer;
}
#left_button { #left_button {
position: absolute; position: absolute;
left: 70; left: 70;
@ -38,6 +53,15 @@
position: absolute; position: absolute;
top: 0; left: 0; bottom: 0; right: 0; top: 0; left: 0; bottom: 0; right: 0;
} }
#report_problem {
position: fixed;
top: 10;
right: 10;
font-family: "Raleway Light", sans-serif;
text-decoration: none;
color: #ddd;
}
</style> </style>
<script> <script>
var handControllerImageURL = null; var handControllerImageURL = null;
@ -152,6 +176,7 @@
<a href="#" id="left_button" onmousedown="cycleLeft()"></a> <a href="#" id="left_button" onmousedown="cycleLeft()"></a>
<a href="#" id="right_button" onmousedown="cycleRight()"></a> <a href="#" id="right_button" onmousedown="cycleRight()"></a>
</div> </div>
<a href="mailto:support@highfidelity.com" id="report_problem">Report Problem</a>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 643 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 909 B

View file

@ -29,7 +29,6 @@ Rectangle {
property bool purchasesReceived: false; property bool purchasesReceived: false;
property bool balanceReceived: false; property bool balanceReceived: false;
property bool securityImageResultReceived: false; property bool securityImageResultReceived: false;
property bool keyFilePathIfExistsResultReceived: false;
property string itemId: ""; property string itemId: "";
property string itemHref: ""; property string itemHref: "";
property double balanceAfterPurchase: 0; property double balanceAfterPurchase: 0;
@ -46,10 +45,15 @@ Rectangle {
root.activeView = "needsLogIn"; root.activeView = "needsLogIn";
} else if (isLoggedIn) { } else if (isLoggedIn) {
root.activeView = "initialize"; root.activeView = "initialize";
commerce.getSecurityImage();
commerce.getKeyFilePathIfExists(); commerce.getKeyFilePathIfExists();
commerce.balance(); }
commerce.inventory(); }
onKeyFilePathIfExistsResult: {
if (path === "" && root.activeView !== "notSetUp") {
root.activeView = "notSetUp";
} else if (path !== "" && root.activeView === "initialize") {
commerce.getSecurityImage();
} }
} }
@ -57,8 +61,8 @@ Rectangle {
securityImageResultReceived = true; securityImageResultReceived = true;
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up" if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
root.activeView = "notSetUp"; root.activeView = "notSetUp";
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") { } else if (exists && root.activeView === "initialize") {
root.activeView = "checkoutMain"; commerce.getWalletAuthenticatedStatus();
} else if (exists) { } else if (exists) {
// just set the source again (to be sure the change was noticed) // just set the source again (to be sure the change was noticed)
securityImage.source = ""; securityImage.source = "";
@ -66,12 +70,17 @@ Rectangle {
} }
} }
onKeyFilePathIfExistsResult: { onWalletAuthenticatedStatusResult: {
keyFilePathIfExistsResultReceived = true; if (!isAuthenticated && !passphraseModal.visible) {
if (path === "" && root.activeView !== "notSetUp") { passphraseModal.visible = true;
root.activeView = "notSetUp"; } else if (isAuthenticated) {
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
root.activeView = "checkoutMain"; root.activeView = "checkoutMain";
if (!balanceReceived) {
commerce.balance();
}
if (!purchasesReceived) {
commerce.inventory();
}
} }
} }
@ -89,8 +98,8 @@ Rectangle {
console.log("Failed to get balance", result.data.message); console.log("Failed to get balance", result.data.message);
} else { } else {
root.balanceReceived = true; root.balanceReceived = true;
hfcBalanceText.text = (parseFloat(result.data.balance/100).toFixed(2)) + " HFC"; hfcBalanceText.text = result.data.balance + " HFC";
balanceAfterPurchase = parseFloat(result.data.balance/100) - root.itemPriceFull/100; balanceAfterPurchase = result.data.balance - root.itemPriceFull;
root.setBuyText(); root.setBuyText();
} }
} }
@ -110,10 +119,6 @@ Rectangle {
} }
} }
HifiWallet.SecurityImageModel {
id: securityImageModel;
}
// //
// TITLE BAR START // TITLE BAR START
// //
@ -195,7 +200,6 @@ Rectangle {
securityImageResultReceived = false; securityImageResultReceived = false;
purchasesReceived = false; purchasesReceived = false;
balanceReceived = false; balanceReceived = false;
keyFilePathIfExistsResultReceived = false;
commerce.getLoginStatus(); commerce.getLoginStatus();
} }
} }
@ -221,7 +225,20 @@ Rectangle {
} }
} }
HifiWallet.PassphraseModal {
id: passphraseModal;
visible: false;
anchors.top: titleBarContainer.bottom;
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
Connections {
onSendSignalToParent: {
sendToScript(msg);
}
}
}
// //
// "WALLET NOT SET UP" START // "WALLET NOT SET UP" START
@ -553,7 +570,7 @@ Rectangle {
} }
RalewayRegular { RalewayRegular {
id: balanceAfterPurchaseText; id: balanceAfterPurchaseText;
text: balanceAfterPurchase.toFixed(2) + " HFC"; text: balanceAfterPurchase + " HFC";
// Text size // Text size
size: balanceAfterPurchaseTextLabel.size; size: balanceAfterPurchaseTextLabel.size;
// Anchors // Anchors
@ -648,7 +665,7 @@ Rectangle {
sendToScript({method: 'checkout_goToPurchases'}); sendToScript({method: 'checkout_goToPurchases'});
} }
} }
RalewayRegular { RalewayRegular {
id: buyText; id: buyText;
// Text size // Text size
@ -687,7 +704,7 @@ Rectangle {
anchors.bottom: root.bottom; anchors.bottom: root.bottom;
anchors.left: parent.left; anchors.left: parent.left;
anchors.right: parent.right; anchors.right: parent.right;
RalewayRegular { RalewayRegular {
id: completeText; id: completeText;
text: "<b>Purchase Complete!</b><br><br>You bought <b>" + (itemNameText.text) + "</b> by <b>" + (itemAuthorText.text) + "</b>"; text: "<b>Purchase Complete!</b><br><br>You bought <b>" + (itemNameText.text) + "</b> by <b>" + (itemAuthorText.text) + "</b>";
@ -706,7 +723,7 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter; horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
} }
Item { Item {
id: checkoutSuccessActionButtonsContainer; id: checkoutSuccessActionButtonsContainer;
// Size // Size
@ -756,7 +773,7 @@ Rectangle {
} }
} }
} }
Item { Item {
id: continueShoppingButtonContainer; id: continueShoppingButtonContainer;
// Size // Size
@ -799,7 +816,7 @@ Rectangle {
anchors.bottom: root.bottom; anchors.bottom: root.bottom;
anchors.left: parent.left; anchors.left: parent.left;
anchors.right: parent.right; anchors.right: parent.right;
RalewayRegular { RalewayRegular {
id: failureHeaderText; id: failureHeaderText;
text: "<b>Purchase Failed.</b><br>Your Purchases and HFC balance haven't changed."; text: "<b>Purchase Failed.</b><br>Your Purchases and HFC balance haven't changed.";
@ -818,7 +835,7 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter; horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
} }
RalewayRegular { RalewayRegular {
id: failureErrorText; id: failureErrorText;
// Text size // Text size
@ -836,7 +853,7 @@ Rectangle {
horizontalAlignment: Text.AlignHCenter; horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
} }
Item { Item {
id: backToMarketplaceButtonContainer; id: backToMarketplaceButtonContainer;
// Size // Size
@ -892,7 +909,7 @@ Rectangle {
itemNameText.text = message.params.itemName; itemNameText.text = message.params.itemName;
itemAuthorText.text = message.params.itemAuthor; itemAuthorText.text = message.params.itemAuthor;
root.itemPriceFull = message.params.itemPrice; root.itemPriceFull = message.params.itemPrice;
itemPriceText.text = root.itemPriceFull === 0 ? "Free" : "<b>" + (parseFloat(root.itemPriceFull/100).toFixed(2)) + " HFC</b>"; itemPriceText.text = root.itemPriceFull === 0 ? "Free" : "<b>" + root.itemPriceFull + " HFC</b>";
itemHref = message.params.itemHref; itemHref = message.params.itemHref;
if (itemHref.indexOf('.json') === -1) { if (itemHref.indexOf('.json') === -1) {
root.itemIsJson = false; root.itemIsJson = false;

View file

@ -28,7 +28,6 @@ Rectangle {
property string activeView: "initialize"; property string activeView: "initialize";
property string referrerURL: ""; property string referrerURL: "";
property bool securityImageResultReceived: false; property bool securityImageResultReceived: false;
property bool keyFilePathIfExistsResultReceived: false;
property bool purchasesReceived: false; property bool purchasesReceived: false;
property bool punctuationMode: false; property bool punctuationMode: false;
// Style // Style
@ -41,9 +40,15 @@ Rectangle {
root.activeView = "needsLogIn"; root.activeView = "needsLogIn";
} else if (isLoggedIn) { } else if (isLoggedIn) {
root.activeView = "initialize"; root.activeView = "initialize";
commerce.getSecurityImage();
commerce.getKeyFilePathIfExists(); commerce.getKeyFilePathIfExists();
commerce.inventory(); }
}
onKeyFilePathIfExistsResult: {
if (path === "" && root.activeView !== "notSetUp") {
root.activeView = "notSetUp";
} else if (path !== "" && root.activeView === "initialize") {
commerce.getSecurityImage();
} }
} }
@ -51,8 +56,8 @@ Rectangle {
securityImageResultReceived = true; securityImageResultReceived = true;
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up" if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
root.activeView = "notSetUp"; root.activeView = "notSetUp";
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") { } else if (exists && root.activeView === "initialize") {
root.activeView = "purchasesMain"; commerce.getWalletAuthenticatedStatus();
} else if (exists) { } else if (exists) {
// just set the source again (to be sure the change was noticed) // just set the source again (to be sure the change was noticed)
securityImage.source = ""; securityImage.source = "";
@ -60,12 +65,12 @@ Rectangle {
} }
} }
onKeyFilePathIfExistsResult: { onWalletAuthenticatedStatusResult: {
keyFilePathIfExistsResultReceived = true; if (!isAuthenticated && !passphraseModal.visible) {
if (path === "" && root.activeView !== "notSetUp") { passphraseModal.visible = true;
root.activeView = "notSetUp"; } else if (isAuthenticated) {
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") {
root.activeView = "purchasesMain"; root.activeView = "purchasesMain";
commerce.inventory();
} }
} }
@ -74,7 +79,9 @@ Rectangle {
if (result.status !== 'success') { if (result.status !== 'success') {
console.log("Failed to get purchases", result.message); console.log("Failed to get purchases", result.message);
} else { } else {
purchasesModel.clear();
purchasesModel.append(result.data.assets); purchasesModel.append(result.data.assets);
filteredPurchasesModel.clear();
filteredPurchasesModel.append(result.data.assets); filteredPurchasesModel.append(result.data.assets);
} }
} }
@ -164,7 +171,6 @@ Rectangle {
Component.onCompleted: { Component.onCompleted: {
securityImageResultReceived = false; securityImageResultReceived = false;
purchasesReceived = false; purchasesReceived = false;
keyFilePathIfExistsResultReceived = false;
commerce.getLoginStatus(); commerce.getLoginStatus();
} }
} }
@ -189,6 +195,21 @@ Rectangle {
commerce.getLoginStatus(); commerce.getLoginStatus();
} }
} }
HifiWallet.PassphraseModal {
id: passphraseModal;
visible: false;
anchors.top: titleBarContainer.bottom;
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
Connections {
onSendSignalToParent: {
sendToScript(msg);
}
}
}
// //
// "WALLET NOT SET UP" START // "WALLET NOT SET UP" START

View file

@ -31,6 +31,7 @@ Item {
// "Unavailable" // "Unavailable"
RalewayRegular { RalewayRegular {
id: helpText;
text: "Help me!"; text: "Help me!";
// Anchors // Anchors
anchors.fill: parent; anchors.fill: parent;
@ -43,6 +44,34 @@ Item {
horizontalAlignment: Text.AlignHCenter; horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
} }
HifiControlsUit.Button {
color: hifi.buttons.black;
colorScheme: hifi.colorSchemes.dark;
anchors.bottom: resetButton.top;
anchors.bottomMargin: 15;
anchors.horizontalCenter: parent.horizontalCenter;
height: 50;
width: 250;
text: "DEBUG: Clear Cached Passphrase";
onClicked: {
commerce.setPassphrase("");
}
}
HifiControlsUit.Button {
id: resetButton;
color: hifi.buttons.red;
colorScheme: hifi.colorSchemes.dark;
anchors.bottom: helpText.bottom;
anchors.bottomMargin: 15;
anchors.horizontalCenter: parent.horizontalCenter;
height: 50;
width: 250;
text: "DEBUG: Reset Wallet!";
onClicked: {
commerce.reset();
sendSignalToWallet({method: 'walletReset'});
}
}
// //
// FUNCTION DEFINITIONS START // FUNCTION DEFINITIONS START

View file

@ -0,0 +1,304 @@
//
// PassphraseModal.qml
// qml/hifi/commerce/wallet
//
// PassphraseModal
//
// Created by Zach Fox on 2017-08-31
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import Hifi 1.0 as Hifi
import QtQuick 2.5
import QtQuick.Controls 1.4
import "../../../styles-uit"
import "../../../controls-uit" as HifiControlsUit
import "../../../controls" as HifiControls
// references XXX from root context
Item {
HifiConstants { id: hifi; }
id: root;
z: 998;
property bool keyboardRaised: false;
Hifi.QmlCommerce {
id: commerce;
onSecurityImageResult: {
passphraseModalSecurityImage.source = "";
passphraseModalSecurityImage.source = "image://security/securityImage";
}
onWalletAuthenticatedStatusResult: {
submitPassphraseInputButton.enabled = true;
if (!isAuthenticated) {
errorText.text = "Authentication failed - please try again.";
} else {
root.visible = false;
}
}
}
// This object is always used in a popup.
// This MouseArea is used to prevent a user from being
// able to click on a button/mouseArea underneath the popup.
MouseArea {
anchors.fill: parent;
propagateComposedEvents: false;
}
// This will cause a bug -- if you bring up passphrase selection in HUD mode while
// in HMD while having HMD preview enabled, then move, then finish passphrase selection,
// HMD preview will stay off.
// TODO: Fix this unlikely bug
onVisibleChanged: {
if (visible) {
passphraseField.focus = true;
sendSignalToParent({method: 'disableHmdPreview'});
} else {
sendSignalToParent({method: 'maybeEnableHmdPreview'});
}
}
// Background rectangle
Rectangle {
anchors.fill: parent;
color: "black";
opacity: 0.9;
}
Rectangle {
anchors.top: parent.top;
anchors.left: parent.left;
anchors.right: parent.right;
height: 250;
color: hifi.colors.baseGray;
RalewaySemiBold {
id: instructionsText;
text: "Enter Wallet Passphrase";
size: 16;
anchors.top: parent.top;
anchors.topMargin: 30;
anchors.left: parent.left;
anchors.leftMargin: 16;
width: passphraseField.width;
height: paintedHeight;
// Style
color: hifi.colors.faintGray;
// Alignment
horizontalAlignment: Text.AlignLeft;
}
HifiControlsUit.TextField {
id: passphraseField;
anchors.top: instructionsText.bottom;
anchors.topMargin: 4;
anchors.left: instructionsText.left;
width: 280;
height: 50;
echoMode: TextInput.Password;
placeholderText: "passphrase";
onFocusChanged: {
root.keyboardRaised = focus;
}
MouseArea {
anchors.fill: parent;
onClicked: {
parent.focus = true;
root.keyboardRaised = true;
}
}
onAccepted: {
submitPassphraseInputButton.enabled = false;
commerce.setPassphrase(passphraseField.text);
}
}
// Show passphrase text
HifiControlsUit.CheckBox {
id: showPassphrase;
colorScheme: hifi.colorSchemes.dark;
anchors.left: passphraseField.left;
anchors.top: passphraseField.bottom;
anchors.topMargin: 8;
height: 30;
text: "Show passphrase as plain text";
boxSize: 24;
onClicked: {
passphraseField.echoMode = checked ? TextInput.Normal : TextInput.Password;
}
}
// Security Image
Item {
id: securityImageContainer;
// Anchors
anchors.top: instructionsText.top;
anchors.left: passphraseField.right;
anchors.leftMargin: 12;
anchors.right: parent.right;
Image {
id: passphraseModalSecurityImage;
anchors.top: parent.top;
anchors.horizontalCenter: parent.horizontalCenter;
height: 75;
width: height;
fillMode: Image.PreserveAspectFit;
mipmap: true;
source: "image://security/securityImage";
cache: false;
onVisibleChanged: {
commerce.getSecurityImage();
}
}
Image {
id: passphraseModalSecurityImageOverlay;
source: "images/lockOverlay.png";
width: passphraseModalSecurityImage.width * 0.45;
height: passphraseModalSecurityImage.height * 0.45;
anchors.bottom: passphraseModalSecurityImage.bottom;
anchors.right: passphraseModalSecurityImage.right;
mipmap: true;
opacity: 0.9;
}
// "Security image" text below pic
RalewayRegular {
text: "security image";
// Text size
size: 12;
// Anchors
anchors.top: passphraseModalSecurityImage.bottom;
anchors.topMargin: 4;
anchors.left: securityImageContainer.left;
anchors.right: securityImageContainer.right;
height: paintedHeight;
// Style
color: hifi.colors.faintGray;
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
}
}
// Error text above buttons
RalewaySemiBold {
id: errorText;
text: "";
// Text size
size: 16;
// Anchors
anchors.bottom: passphrasePopupActionButtonsContainer.top;
anchors.bottomMargin: 4;
anchors.left: parent.left;
anchors.leftMargin: 16;
anchors.right: parent.right;
anchors.rightMargin: 16;
height: 30;
// Style
color: hifi.colors.redHighlight;
// Alignment
horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignVCenter;
}
//
// ACTION BUTTONS START
//
Item {
id: passphrasePopupActionButtonsContainer;
// Size
width: root.width;
height: 50;
// Anchors
anchors.left: parent.left;
anchors.bottom: parent.bottom;
anchors.bottomMargin: 10;
// "Cancel" button
HifiControlsUit.Button {
id: cancelPassphraseInputButton;
color: hifi.buttons.black;
colorScheme: hifi.colorSchemes.dark;
anchors.top: parent.top;
height: 40;
anchors.left: parent.left;
anchors.leftMargin: 20;
width: parent.width/2 - anchors.leftMargin*2;
text: "Cancel"
onClicked: {
sendSignalToParent({method: 'passphrasePopup_cancelClicked'});
}
}
// "Submit" button
HifiControlsUit.Button {
id: submitPassphraseInputButton;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.dark;
anchors.top: parent.top;
height: 40;
anchors.right: parent.right;
anchors.rightMargin: 20;
width: parent.width/2 - anchors.rightMargin*2;
text: "Submit"
onClicked: {
submitPassphraseInputButton.enabled = false;
commerce.setPassphrase(passphraseField.text);
}
}
}
}
Item {
id: keyboardContainer;
z: 999;
visible: keyboard.raised;
property bool punctuationMode: false;
anchors {
bottom: parent.bottom;
left: parent.left;
right: parent.right;
}
Image {
id: lowerKeyboardButton;
source: "images/lowerKeyboard.png";
anchors.horizontalCenter: parent.horizontalCenter;
anchors.bottom: keyboard.top;
height: 30;
width: 120;
MouseArea {
anchors.fill: parent;
onClicked: {
root.keyboardRaised = false;
}
}
}
HifiControlsUit.Keyboard {
id: keyboard;
raised: HMD.mounted && root.keyboardRaised;
numeric: parent.punctuationMode;
anchors {
bottom: parent.bottom;
left: parent.left;
right: parent.right;
}
}
}
signal sendSignalToParent(var msg);
}

View file

@ -40,8 +40,8 @@ Item {
passphrasePageSecurityImage.source = "image://security/securityImage"; passphrasePageSecurityImage.source = "image://security/securityImage";
} }
onPassphraseSetupStatusResult: { onWalletAuthenticatedStatusResult: {
sendMessageToLightbox({method: 'statusResult', status: passphraseIsSetup}); sendMessageToLightbox({method: 'statusResult', status: isAuthenticated});
} }
} }
@ -58,10 +58,6 @@ Item {
} }
} }
SecurityImageModel {
id: gridModel;
}
HifiControlsUit.TextField { HifiControlsUit.TextField {
id: passphraseField; id: passphraseField;
anchors.top: parent.top; anchors.top: parent.top;
@ -199,7 +195,7 @@ Item {
// Text below TextFields // Text below TextFields
RalewaySemiBold { RalewaySemiBold {
id: passwordReqs; id: passwordReqs;
text: "Passphrase must be at least 4 characters"; text: "Passphrase must be at least 3 characters";
// Text size // Text size
size: 16; size: 16;
// Anchors // Anchors
@ -256,7 +252,7 @@ Item {
} }
function validateAndSubmitPassphrase() { function validateAndSubmitPassphrase() {
if (passphraseField.text.length < 4) { if (passphraseField.text.length < 3) {
setErrorText("Passphrase too short."); setErrorText("Passphrase too short.");
return false; return false;
} else if (passphraseField.text !== passphraseFieldAgain.text) { } else if (passphraseField.text !== passphraseFieldAgain.text) {

View file

@ -26,8 +26,6 @@ Rectangle {
id: root; id: root;
property string activeView: "initialize"; property string activeView: "initialize";
property bool securityImageResultReceived: false;
property bool keyFilePathIfExistsResultReceived: false;
property bool keyboardRaised: false; property bool keyboardRaised: false;
// Style // Style
@ -40,25 +38,30 @@ Rectangle {
root.activeView = "needsLogIn"; root.activeView = "needsLogIn";
} else if (isLoggedIn) { } else if (isLoggedIn) {
root.activeView = "initialize"; root.activeView = "initialize";
commerce.getSecurityImage();
commerce.getKeyFilePathIfExists(); commerce.getKeyFilePathIfExists();
} }
} }
onSecurityImageResult: { onKeyFilePathIfExistsResult: {
securityImageResultReceived = true; if (path === "" && root.activeView !== "notSetUp") {
if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
root.activeView = "notSetUp"; root.activeView = "notSetUp";
} else if (root.securityImageResultReceived && exists && root.keyFilePathIfExistsResultReceived && root.activeView === "initialize") { } else if (path !== "" && root.activeView === "initialize") {
root.activeView = "walletHome"; commerce.getSecurityImage();
} }
} }
onKeyFilePathIfExistsResult: { onSecurityImageResult: {
keyFilePathIfExistsResultReceived = true; if (!exists && root.activeView !== "notSetUp") { // "If security image is not set up"
if (path === "" && root.activeView !== "notSetUp") {
root.activeView = "notSetUp"; root.activeView = "notSetUp";
} else if (root.securityImageResultReceived && root.keyFilePathIfExistsResultReceived && path !== "" && root.activeView === "initialize") { } else if (exists && root.activeView === "initialize") {
commerce.getWalletAuthenticatedStatus();
}
}
onWalletAuthenticatedStatusResult: {
if (!isAuthenticated && passphraseModal && !passphraseModal.visible) {
passphraseModal.visible = true;
} else if (isAuthenticated) {
root.activeView = "walletHome"; root.activeView = "walletHome";
} }
} }
@ -89,7 +92,8 @@ Rectangle {
if (msg.method === 'walletSetup_cancelClicked') { if (msg.method === 'walletSetup_cancelClicked') {
walletSetupLightbox.visible = false; walletSetupLightbox.visible = false;
} else if (msg.method === 'walletSetup_finished') { } else if (msg.method === 'walletSetup_finished') {
root.activeView = "walletHome"; root.activeView = "initialize";
commerce.getLoginStatus();
} else if (msg.method === 'walletSetup_raiseKeyboard') { } else if (msg.method === 'walletSetup_raiseKeyboard') {
root.keyboardRaised = true; root.keyboardRaised = true;
} else if (msg.method === 'walletSetup_lowerKeyboard') { } else if (msg.method === 'walletSetup_lowerKeyboard') {
@ -107,7 +111,7 @@ Rectangle {
anchors.centerIn: walletSetupLightboxContainer; anchors.centerIn: walletSetupLightboxContainer;
width: walletSetupLightboxContainer.width - 50; width: walletSetupLightboxContainer.width - 50;
height: walletSetupLightboxContainer.height - 50; height: walletSetupLightboxContainer.height - 50;
Connections { Connections {
onSendSignalToWallet: { onSendSignalToWallet: {
if (msg.method === 'walletSetup_raiseKeyboard') { if (msg.method === 'walletSetup_raiseKeyboard') {
@ -127,7 +131,7 @@ Rectangle {
anchors.centerIn: walletSetupLightboxContainer; anchors.centerIn: walletSetupLightboxContainer;
width: walletSetupLightboxContainer.width - 50; width: walletSetupLightboxContainer.width - 50;
height: walletSetupLightboxContainer.height - 50; height: walletSetupLightboxContainer.height - 50;
Connections { Connections {
onSendSignalToWallet: { onSendSignalToWallet: {
sendToScript(msg); sendToScript(msg);
@ -196,7 +200,7 @@ Rectangle {
commerce.getLoginStatus(); commerce.getLoginStatus();
} }
} }
NeedsLogIn { NeedsLogIn {
id: needsLogIn; id: needsLogIn;
visible: root.activeView === "needsLogIn"; visible: root.activeView === "needsLogIn";
@ -218,6 +222,21 @@ Rectangle {
} }
} }
PassphraseModal {
id: passphraseModal;
visible: false;
anchors.top: titleBarContainer.bottom;
anchors.bottom: parent.bottom;
anchors.left: parent.left;
anchors.right: parent.right;
Connections {
onSendSignalToParent: {
sendToScript(msg);
}
}
}
NotSetUp { NotSetUp {
id: notSetUp; id: notSetUp;
visible: root.activeView === "notSetUp"; visible: root.activeView === "notSetUp";
@ -225,7 +244,7 @@ Rectangle {
anchors.bottom: tabButtonsContainer.top; anchors.bottom: tabButtonsContainer.top;
anchors.left: parent.left; anchors.left: parent.left;
anchors.right: parent.right; anchors.right: parent.right;
Connections { Connections {
onSendSignalToWallet: { onSendSignalToWallet: {
if (msg.method === 'setUpClicked') { if (msg.method === 'setUpClicked') {
@ -296,6 +315,14 @@ Rectangle {
anchors.leftMargin: 16; anchors.leftMargin: 16;
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 16; anchors.rightMargin: 16;
Connections {
onSendSignalToWallet: {
if (msg.method === 'walletReset') {
sendToScript(msg);
}
}
}
} }
@ -510,7 +537,7 @@ Rectangle {
} }
// //
// TAB BUTTONS END // TAB BUTTONS END
// //
Item { Item {
id: keyboardContainer; id: keyboardContainer;

View file

@ -24,6 +24,7 @@ Item {
HifiConstants { id: hifi; } HifiConstants { id: hifi; }
id: root; id: root;
property bool historyReceived: false;
Hifi.QmlCommerce { Hifi.QmlCommerce {
id: commerce; id: commerce;
@ -37,13 +38,14 @@ Item {
} }
onBalanceResult : { onBalanceResult : {
balanceText.text = parseFloat(result.data.balance/100).toFixed(2); balanceText.text = result.data.balance;
} }
onHistoryResult : { onHistoryResult : {
historyReceived = true;
if (result.status === 'success') { if (result.status === 'success') {
var txt = result.data.history.map(function (h) { return h.text; }).join("<hr>"); transactionHistoryModel.clear();
transactionHistoryText.text = txt; transactionHistoryModel.append(result.data.history);
} }
} }
} }
@ -86,13 +88,14 @@ Item {
height: 60; height: 60;
Rectangle { Rectangle {
id: hfcBalanceField; id: hfcBalanceField;
color: hifi.colors.darkGray;
anchors.right: parent.right; anchors.right: parent.right;
anchors.left: parent.left; anchors.left: parent.left;
anchors.bottom: parent.bottom; anchors.bottom: parent.bottom;
height: parent.height - 15; height: parent.height - 15;
// "HFC" balance label // "HFC" balance label
RalewayRegular { FiraSansRegular {
id: balanceLabel; id: balanceLabel;
text: "HFC"; text: "HFC";
// Text size // Text size
@ -104,13 +107,14 @@ Item {
anchors.rightMargin: 4; anchors.rightMargin: 4;
width: paintedWidth; width: paintedWidth;
// Style // Style
color: hifi.colors.darkGray; color: hifi.colors.lightGrayText;
// Alignment // Alignment
horizontalAlignment: Text.AlignRight; horizontalAlignment: Text.AlignRight;
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
historyReceived = false;
commerce.balance(); commerce.balance();
commerce.history(); commerce.history();
} }
@ -118,7 +122,7 @@ Item {
} }
// Balance Text // Balance Text
FiraSansRegular { FiraSansSemiBold {
id: balanceText; id: balanceText;
text: "--"; text: "--";
// Text size // Text size
@ -130,7 +134,7 @@ Item {
anchors.right: balanceLabel.left; anchors.right: balanceLabel.left;
anchors.rightMargin: 4; anchors.rightMargin: 4;
// Style // Style
color: hifi.colors.darkGray; color: hifi.colors.lightGrayText;
// Alignment // Alignment
horizontalAlignment: Text.AlignRight; horizontalAlignment: Text.AlignRight;
verticalAlignment: Text.AlignVCenter; verticalAlignment: Text.AlignVCenter;
@ -233,24 +237,66 @@ Item {
// Style // Style
color: hifi.colors.faintGray; color: hifi.colors.faintGray;
} }
ListModel {
id: transactionHistoryModel;
}
Rectangle { Rectangle {
id: transactionHistory;
anchors.top: recentActivityText.bottom; anchors.top: recentActivityText.bottom;
anchors.topMargin: 4; anchors.topMargin: 4;
anchors.bottom: parent.bottom; anchors.bottom: parent.bottom;
anchors.left: parent.left; anchors.left: parent.left;
anchors.right: parent.right; anchors.right: parent.right;
color: "white";
// some placeholder stuff ListView {
TextArea { id: transactionHistory;
id: transactionHistoryText; anchors.centerIn: parent;
text: "<hr>history unavailable<hr>"; width: parent.width - 12;
textFormat: TextEdit.AutoText; height: parent.height - 12;
font.pointSize: 10; visible: transactionHistoryModel.count !== 0;
clip: true;
model: transactionHistoryModel;
delegate: Item {
width: parent.width;
height: transactionText.height + 30;
FiraSansRegular {
id: transactionText;
text: model.text;
// Style
size: 18;
width: parent.width;
height: paintedHeight;
anchors.verticalCenter: parent.verticalCenter;
color: "black";
wrapMode: Text.WordWrap;
// Alignment
horizontalAlignment: Text.AlignLeft;
verticalAlignment: Text.AlignVCenter;
}
HifiControlsUit.Separator {
anchors.left: parent.left;
anchors.right: parent.right;
anchors.bottom: parent.bottom;
}
}
onAtYEndChanged: {
if (transactionHistory.atYEnd) {
console.log("User scrolled to the bottom of 'Recent Activity'.");
// Grab next page of results and append to model
}
}
}
// This should never be visible (since you immediately get 100 HFC)
FiraSansRegular {
id: emptyTransationHistory;
size: 24;
visible: !transactionHistory.visible && root.historyReceived;
text: "Recent Activity Unavailable";
anchors.fill: parent; anchors.fill: parent;
horizontalAlignment: Text.AlignLeft; horizontalAlignment: Text.AlignHCenter;
verticalAlignment: Text.AlignTop; verticalAlignment: Text.AlignVCenter;
} }
} }
} }

View file

@ -24,7 +24,7 @@ Rectangle {
HifiConstants { id: hifi; } HifiConstants { id: hifi; }
id: root; id: root;
property string lastPage: "securityImage"; property string lastPage: "initialize";
// Style // Style
color: hifi.colors.baseGray; color: hifi.colors.baseGray;
@ -39,9 +39,9 @@ Rectangle {
} }
} }
onPassphraseSetupStatusResult: { onWalletAuthenticatedStatusResult: {
securityImageContainer.visible = false; securityImageContainer.visible = false;
if (passphraseIsSetup) { if (isAuthenticated) {
privateKeysReadyContainer.visible = true; privateKeysReadyContainer.visible = true;
} else { } else {
choosePassphraseContainer.visible = true; choosePassphraseContainer.visible = true;
@ -58,16 +58,9 @@ Rectangle {
// //
Item { Item {
id: securityImageContainer; id: securityImageContainer;
visible: false;
// Anchors // Anchors
anchors.fill: parent; anchors.fill: parent;
onVisibleChanged: {
if (visible) {
commerce.getSecurityImage();
}
}
Item { Item {
id: securityImageTitle; id: securityImageTitle;
// Size // Size
@ -124,7 +117,7 @@ Rectangle {
anchors.right: parent.right; anchors.right: parent.right;
anchors.rightMargin: 16; anchors.rightMargin: 16;
height: 280; height: 280;
Connections { Connections {
onSendSignalToWallet: { onSendSignalToWallet: {
sendSignalToWallet(msg); sendSignalToWallet(msg);
@ -217,7 +210,7 @@ Rectangle {
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
commerce.getPassphraseSetupStatus(); commerce.getWalletAuthenticatedStatus();
} }
} }

View file

@ -1,5 +1,6 @@
import QtQuick 2.5 import QtQuick 2.5
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.3
import "../../styles-uit" import "../../styles-uit"
import "../audio" as HifiAudio import "../audio" as HifiAudio
@ -109,15 +110,45 @@ Item {
} }
} }
RalewaySemiBold { Item {
id: usernameText width: 150
text: tabletRoot.username height: 50
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 20 anchors.rightMargin: 30
horizontalAlignment: Text.AlignRight anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 20
color: "#afafaf" ColumnLayout {
anchors.fill: parent
RalewaySemiBold {
text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in")
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
font.pixelSize: 20
color: "#afafaf"
}
RalewaySemiBold {
visible: Account.loggedIn
height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0
text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : ""
horizontalAlignment: Text.AlignRight
anchors.right: parent.right
font.pixelSize: 20
color: "#afafaf"
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if (!Account.loggedIn) {
DialogsManager.showLoginDialog()
} else {
Account.logOut()
}
}
}
} }
} }

View file

@ -8,6 +8,7 @@ Item {
id: tabletRoot id: tabletRoot
objectName: "tabletRoot" objectName: "tabletRoot"
property string username: "Unknown user" property string username: "Unknown user"
property string usernameShort: "Unknown user"
property var rootMenu; property var rootMenu;
property var openModal: null; property var openModal: null;
property var openMessage: null; property var openMessage: null;
@ -157,6 +158,11 @@ Item {
function setUsername(newUsername) { function setUsername(newUsername) {
username = newUsername; username = newUsername;
usernameShort = newUsername.substring(0, 8);
if (newUsername.length > 8) {
usernameShort = usernameShort + "..."
}
} }
ListModel { ListModel {

View file

@ -4,6 +4,7 @@ import QtQuick.Controls 1.4
StateImage { StateImage {
id: button id: button
property string captionColorOverride: ""
property bool buttonEnabled: true property bool buttonEnabled: true
property bool isActive: false property bool isActive: false
property bool isEntered: false property bool isEntered: false
@ -97,7 +98,7 @@ StateImage {
Text { Text {
id: caption id: caption
color: button.isActive ? "#000000" : "#ffffff" color: captionColorOverride !== "" ? captionColorOverride: (button.isActive ? "#000000" : "#ffffff")
text: button.isActive ? (button.isEntered ? button.activeHoverText : button.activeText) : (button.isEntered ? button.hoverText : button.text) text: button.isActive ? (button.isEntered ? button.activeHoverText : button.activeText) : (button.isEntered ? button.hoverText : button.text)
font.bold: false font.bold: false
font.pixelSize: 9 font.pixelSize: 9

View file

@ -166,6 +166,7 @@
#include "scripting/WindowScriptingInterface.h" #include "scripting/WindowScriptingInterface.h"
#include "scripting/ControllerScriptingInterface.h" #include "scripting/ControllerScriptingInterface.h"
#include "scripting/RatesScriptingInterface.h" #include "scripting/RatesScriptingInterface.h"
#include "scripting/SelectionScriptingInterface.h"
#if defined(Q_OS_MAC) || defined(Q_OS_WIN) #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
#include "SpeechRecognizer.h" #include "SpeechRecognizer.h"
#endif #endif
@ -675,6 +676,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<Snapshot>(); DependencyManager::set<Snapshot>();
DependencyManager::set<CloseEventSender>(); DependencyManager::set<CloseEventSender>();
DependencyManager::set<ResourceManager>(); DependencyManager::set<ResourceManager>();
DependencyManager::set<SelectionScriptingInterface>();
DependencyManager::set<ContextOverlayInterface>(); DependencyManager::set<ContextOverlayInterface>();
DependencyManager::set<Ledger>(); DependencyManager::set<Ledger>();
DependencyManager::set<Wallet>(); DependencyManager::set<Wallet>();
@ -2318,6 +2320,7 @@ void Application::initializeUi() {
surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor()); surfaceContext->setContextProperty("ApplicationCompositor", &getApplicationCompositor());
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance()); surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
@ -5641,17 +5644,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
} }
renderArgs->_debugFlags = renderDebugFlags; renderArgs->_debugFlags = renderDebugFlags;
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, transaction); //ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, transaction);
RenderArgs::OutlineFlags renderOutlineFlags = RenderArgs::RENDER_OUTLINE_NONE;
auto contextOverlayInterface = DependencyManager::get<ContextOverlayInterface>();
if (contextOverlayInterface->getEnabled()) {
if (DependencyManager::get<ContextOverlayInterface>()->getIsInMarketplaceInspectionMode()) {
renderOutlineFlags = RenderArgs::RENDER_OUTLINE_MARKETPLACE_MODE;
} else {
renderOutlineFlags = RenderArgs::RENDER_OUTLINE_WIREFRAMES;
}
}
renderArgs->_outlineFlags = renderOutlineFlags;
} }
} }
@ -6118,6 +6110,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
auto entityScriptServerLog = DependencyManager::get<EntityScriptServerLogClient>(); auto entityScriptServerLog = DependencyManager::get<EntityScriptServerLogClient>();
scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data()); scriptEngine->registerGlobalObject("EntityScriptServerLog", entityScriptServerLog.data());
scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance()); scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance());
scriptEngine->registerGlobalObject("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue); qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue);

View file

@ -1912,6 +1912,17 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
const bool shouldDrawHead = shouldRenderHead(renderArgs); const bool shouldDrawHead = shouldRenderHead(renderArgs);
if (shouldDrawHead != _prevShouldDrawHead) { if (shouldDrawHead != _prevShouldDrawHead) {
_skeletonModel->setEnableCauterization(!shouldDrawHead); _skeletonModel->setEnableCauterization(!shouldDrawHead);
for (int i = 0; i < _attachmentData.size(); i++) {
if (_attachmentData[i].jointName.compare("Head", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Neck", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("LeftEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
_attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene());
}
}
} }
_prevShouldDrawHead = shouldDrawHead; _prevShouldDrawHead = shouldDrawHead;
} }

View file

@ -11,6 +11,7 @@
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray> #include <QJsonArray>
#include <QTimeZone>
#include <QJsonDocument> #include <QJsonDocument>
#include "AccountManager.h" #include "AccountManager.h"
#include "Wallet.h" #include "Wallet.h"
@ -45,7 +46,6 @@ Handler(buy)
Handler(receiveAt) Handler(receiveAt)
Handler(balance) Handler(balance)
Handler(inventory) Handler(inventory)
Handler(history)
void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request) { void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request) {
auto accountManager = DependencyManager::get<AccountManager>(); auto accountManager = DependencyManager::get<AccountManager>();
@ -108,6 +108,71 @@ void Ledger::inventory(const QStringList& keys) {
keysQuery("inventory", "inventorySuccess", "inventoryFailure"); keysQuery("inventory", "inventorySuccess", "inventoryFailure");
} }
QString nameFromKey(const QString& key, const QStringList& publicKeys) {
if (key.isNull() || key.isEmpty()) {
return "<b>Marketplace</b>";
}
if (publicKeys.contains(key)) {
return "You";
}
return "<b>Someone</b>";
}
void Ledger::historySuccess(QNetworkReply& reply) {
// here we send a historyResult with some extra stuff in it
// Namely, the styled text we'd like to show. The issue is the
// QML cannot do that easily since it doesn't know what the wallet
// public key(s) are. Let's keep it that way
QByteArray response = reply.readAll();
QJsonObject data = QJsonDocument::fromJson(response).object();
// we will need the array of public keys from the wallet
auto wallet = DependencyManager::get<Wallet>();
auto keys = wallet->listPublicKeys();
// now we need to loop through the transactions and add fancy text...
auto historyArray = data.find("data").value().toObject().find("history").value().toArray();
QJsonArray newHistoryArray;
// TODO: do this with 0 copies if possible
for(auto it = historyArray.begin(); it != historyArray.end(); it++) {
auto valueObject = (*it).toObject();
QString from = nameFromKey(valueObject["sender_key"].toString(), keys);
QString to = nameFromKey(valueObject["recipient_key"].toString(), keys);
// turns out on my machine, toLocalTime convert to some weird timezone, yet the
// systemTimeZone is correct. To avoid a strange bug with other's systems too, lets
// be explicit
#ifdef Q_OS_MAC
QDateTime createdAt = QDateTime::fromTime_t(valueObject["created_at"].toInt(), Qt::UTC);
#else
QDateTime createdAt = QDateTime::fromSecsSinceEpoch(valueObject["created_at"].toInt(), Qt::UTC);
#endif
QDateTime localCreatedAt = createdAt.toTimeZone(QTimeZone::systemTimeZone());
valueObject["text"] = QString("%1 sent %2 <b>%3 %4</b> on %5 with message \"%6\"").
arg(from, to, QString::number(valueObject["quantity"].toInt()), valueObject["asset_title"].toString(), localCreatedAt.toString(Qt::SystemLocaleShortDate), valueObject["message"].toString());
newHistoryArray.push_back(valueObject);
}
// now copy the rest of the json -- this is inefficient
// TODO: try to do this without making copies
QJsonObject newData;
newData["status"] = "success";
QJsonObject newDataData;
newDataData["history"] = newHistoryArray;
newData["data"] = newDataData;
emit historyResult(newData);
}
void Ledger::historyFailure(QNetworkReply& reply) {
failResponse("history", reply);
}
void Ledger::history(const QStringList& keys) { void Ledger::history(const QStringList& keys) {
keysQuery("history", "historySuccess", "historyFailure"); keysQuery("history", "historySuccess", "historyFailure");
} }
// The api/failResponse is called just for the side effect of logging.
void Ledger::resetSuccess(QNetworkReply& reply) { apiResponse("reset", reply); }
void Ledger::resetFailure(QNetworkReply& reply) { failResponse("reset", reply); }
void Ledger::reset() {
send("reset_user_hfc_account", "resetSuccess", "resetFailure", QNetworkAccessManager::PutOperation, QJsonObject());
}

View file

@ -29,6 +29,7 @@ public:
void balance(const QStringList& keys); void balance(const QStringList& keys);
void inventory(const QStringList& keys); void inventory(const QStringList& keys);
void history(const QStringList& keys); void history(const QStringList& keys);
void reset();
signals: signals:
void buyResult(QJsonObject result); void buyResult(QJsonObject result);
@ -48,6 +49,8 @@ public slots:
void inventoryFailure(QNetworkReply& reply); void inventoryFailure(QNetworkReply& reply);
void historySuccess(QNetworkReply& reply); void historySuccess(QNetworkReply& reply);
void historyFailure(QNetworkReply& reply); void historyFailure(QNetworkReply& reply);
void resetSuccess(QNetworkReply& reply);
void resetFailure(QNetworkReply& reply);
private: private:
QJsonObject apiResponse(const QString& label, QNetworkReply& reply); QJsonObject apiResponse(const QString& label, QNetworkReply& reply);

View file

@ -29,6 +29,30 @@ QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult); connect(wallet.data(), &Wallet::keyFilePathIfExistsResult, this, &QmlCommerce::keyFilePathIfExistsResult);
} }
void QmlCommerce::getLoginStatus() {
emit loginStatusResult(DependencyManager::get<AccountManager>()->isLoggedIn());
}
void QmlCommerce::getKeyFilePathIfExists() {
auto wallet = DependencyManager::get<Wallet>();
wallet->sendKeyFilePathIfExists();
}
void QmlCommerce::getWalletAuthenticatedStatus() {
auto wallet = DependencyManager::get<Wallet>();
emit walletAuthenticatedStatusResult(wallet->walletIsAuthenticatedWithPassphrase());
}
void QmlCommerce::getSecurityImage() {
auto wallet = DependencyManager::get<Wallet>();
wallet->getSecurityImage();
}
void QmlCommerce::chooseSecurityImage(const QString& imageFile) {
auto wallet = DependencyManager::get<Wallet>();
wallet->chooseSecurityImage(imageFile);
}
void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) { void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUsername) {
auto ledger = DependencyManager::get<Ledger>(); auto ledger = DependencyManager::get<Ledger>();
auto wallet = DependencyManager::get<Wallet>(); auto wallet = DependencyManager::get<Wallet>();
@ -60,28 +84,19 @@ void QmlCommerce::history() {
ledger->history(wallet->listPublicKeys()); ledger->history(wallet->listPublicKeys());
} }
void QmlCommerce::chooseSecurityImage(const QString& imageFile) {
auto wallet = DependencyManager::get<Wallet>();
wallet->chooseSecurityImage(imageFile);
}
void QmlCommerce::getSecurityImage() {
auto wallet = DependencyManager::get<Wallet>();
wallet->getSecurityImage();
}
void QmlCommerce::getLoginStatus() {
emit loginStatusResult(DependencyManager::get<AccountManager>()->isLoggedIn());
}
void QmlCommerce::setPassphrase(const QString& passphrase) { void QmlCommerce::setPassphrase(const QString& passphrase) {
emit passphraseSetupStatusResult(true); auto wallet = DependencyManager::get<Wallet>();
if (wallet->getPassphrase() && !wallet->getPassphrase()->isEmpty()) {
wallet->changePassphrase(passphrase);
} else {
wallet->setPassphrase(passphrase);
}
getWalletAuthenticatedStatus();
} }
void QmlCommerce::getPassphraseSetupStatus() { void QmlCommerce::reset() {
emit passphraseSetupStatusResult(false); auto ledger = DependencyManager::get<Ledger>();
}
void QmlCommerce::getKeyFilePathIfExists() {
auto wallet = DependencyManager::get<Wallet>(); auto wallet = DependencyManager::get<Wallet>();
wallet->sendKeyFilePathIfExists(); ledger->reset();
wallet->reset();
} }

View file

@ -28,28 +28,33 @@ public:
QmlCommerce(QQuickItem* parent = nullptr); QmlCommerce(QQuickItem* parent = nullptr);
signals: signals:
void loginStatusResult(bool isLoggedIn);
void keyFilePathIfExistsResult(const QString& path);
void securityImageResult(bool exists);
void walletAuthenticatedStatusResult(bool isAuthenticated);
void buyResult(QJsonObject result); void buyResult(QJsonObject result);
// Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and // Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and
// because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain). // because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain).
void balanceResult(QJsonObject result); void balanceResult(QJsonObject result);
void inventoryResult(QJsonObject result); void inventoryResult(QJsonObject result);
void securityImageResult(bool exists);
void loginStatusResult(bool isLoggedIn);
void passphraseSetupStatusResult(bool passphraseIsSetup);
void historyResult(QJsonObject result); void historyResult(QJsonObject result);
void keyFilePathIfExistsResult(const QString& path);
protected: protected:
Q_INVOKABLE void getLoginStatus();
Q_INVOKABLE void getKeyFilePathIfExists();
Q_INVOKABLE void getSecurityImage();
Q_INVOKABLE void getWalletAuthenticatedStatus();
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
Q_INVOKABLE void setPassphrase(const QString& passphrase);
Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = ""); Q_INVOKABLE void buy(const QString& assetId, int cost, const QString& buyerUsername = "");
Q_INVOKABLE void balance(); Q_INVOKABLE void balance();
Q_INVOKABLE void inventory(); Q_INVOKABLE void inventory();
Q_INVOKABLE void history(); Q_INVOKABLE void history();
Q_INVOKABLE void chooseSecurityImage(const QString& imageFile);
Q_INVOKABLE void getSecurityImage(); Q_INVOKABLE void reset();
Q_INVOKABLE void getLoginStatus();
Q_INVOKABLE void setPassphrase(const QString& passphrase);
Q_INVOKABLE void getPassphraseSetupStatus();
Q_INVOKABLE void getKeyFilePathIfExists();
}; };
#endif // hifi_QmlCommerce_h #endif // hifi_QmlCommerce_h

View file

@ -14,6 +14,7 @@
#include "Wallet.h" #include "Wallet.h"
#include "Application.h" #include "Application.h"
#include "ui/ImageProvider.h" #include "ui/ImageProvider.h"
#include "scripting/HMDScriptingInterface.h"
#include <PathUtils.h> #include <PathUtils.h>
#include <OffscreenUi.h> #include <OffscreenUi.h>
@ -55,16 +56,72 @@ QString imageFilePath() {
int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) { int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) {
// just return a hardcoded pwd for now // just return a hardcoded pwd for now
auto passphrase = DependencyManager::get<Wallet>()->getPassphrase(); auto passphrase = DependencyManager::get<Wallet>()->getPassphrase();
if (passphrase) { if (passphrase && !passphrase->isEmpty()) {
strcpy(password, passphrase->toLocal8Bit().constData()); strcpy(password, passphrase->toLocal8Bit().constData());
return static_cast<int>(passphrase->size()); return static_cast<int>(passphrase->size());
} else { } else {
// ok gotta bring up modal dialog... But right now lets just // this shouldn't happen - so lets log it to tell us we have
// just keep it empty // a problem with the flow...
qCCritical(commerce) << "no cached passphrase while decrypting!";
return 0; return 0;
} }
} }
RSA* readKeys(const char* filename) {
FILE* fp;
RSA* key = NULL;
if ((fp = fopen(filename, "rt"))) {
// file opened successfully
qCDebug(commerce) << "opened key file" << filename;
if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) {
// now read private key
qCDebug(commerce) << "read public key";
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
qCDebug(commerce) << "read private key";
fclose(fp);
return key;
}
qCDebug(commerce) << "failed to read private key";
} else {
qCDebug(commerce) << "failed to read public key";
}
fclose(fp);
} else {
qCDebug(commerce) << "failed to open key file" << filename;
}
return key;
}
bool writeKeys(const char* filename, RSA* keys) {
FILE* fp;
bool retval = false;
if ((fp = fopen(filename, "wt"))) {
if (!PEM_write_RSAPublicKey(fp, keys)) {
fclose(fp);
qCDebug(commerce) << "failed to write public key";
QFile(QString(filename)).remove();
return retval;
}
if (!PEM_write_RSAPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
fclose(fp);
qCDebug(commerce) << "failed to write private key";
QFile(QString(filename)).remove();
return retval;
}
retval = true;
qCDebug(commerce) << "wrote keys successfully";
fclose(fp);
} else {
qCDebug(commerce) << "failed to open key file" << filename;
}
return retval;
}
// BEGIN copied code - this will be removed/changed at some point soon // BEGIN copied code - this will be removed/changed at some point soon
// copied (without emits for various signals) from libraries/networking/src/RSAKeypairGenerator.cpp. // copied (without emits for various signals) from libraries/networking/src/RSAKeypairGenerator.cpp.
// We will have a different implementation in practice, but this gives us a start for now // We will have a different implementation in practice, but this gives us a start for now
@ -123,25 +180,9 @@ QPair<QByteArray*, QByteArray*> generateRSAKeypair() {
} }
if (!writeKeys(keyFilePath().toStdString().c_str(), keyPair)) {
// now lets persist them to files qCDebug(commerce) << "couldn't save keys!";
// FIXME: for now I'm appending to the file if it exists. As long as we always put return retval;
// the keys in the same order, this works fine. TODO: verify this will skip over
// anything else (like an embedded image)
FILE* fp;
if ((fp = fopen(keyFilePath().toStdString().c_str(), "at"))) {
if (!PEM_write_RSAPublicKey(fp, keyPair)) {
fclose(fp);
qCDebug(commerce) << "failed to write public key";
return retval;
}
if (!PEM_write_RSAPrivateKey(fp, keyPair, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) {
fclose(fp);
qCDebug(commerce) << "failed to write private key";
return retval;
}
fclose(fp);
} }
RSA_free(keyPair); RSA_free(keyPair);
@ -200,9 +241,6 @@ RSA* readPrivateKey(const char* filename) {
// file opened successfully // file opened successfully
qCDebug(commerce) << "opened key file" << filename; qCDebug(commerce) << "opened key file" << filename;
if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) { if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) {
// cleanup
fclose(fp);
qCDebug(commerce) << "parsed private key file successfully"; qCDebug(commerce) << "parsed private key file successfully";
} else { } else {
@ -214,7 +252,6 @@ RSA* readPrivateKey(const char* filename) {
} }
return key; return key;
} }
static const unsigned char IVEC[16] = "IAmAnIVecYay123"; static const unsigned char IVEC[16] = "IAmAnIVecYay123";
void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) { void initializeAESKeys(unsigned char* ivec, unsigned char* ckey, const QByteArray& salt) {
@ -235,6 +272,10 @@ void Wallet::setPassphrase(const QString& passphrase) {
delete _passphrase; delete _passphrase;
} }
_passphrase = new QString(passphrase); _passphrase = new QString(passphrase);
// no matter what, we now need to clear the keys as they
// need to be read using this passphrase
_publicKeys.clear();
} }
// encrypt some stuff // encrypt some stuff
@ -340,6 +381,38 @@ bool Wallet::decryptFile(const QString& inputFilePath, unsigned char** outputBuf
return true; return true;
} }
bool Wallet::walletIsAuthenticatedWithPassphrase() {
// try to read existing keys if they exist...
// FIXME: initialize OpenSSL elsewhere soon
initialize();
// this should always be false if we don't have a passphrase
// cached yet
if (!_passphrase || _passphrase->isEmpty()) {
return false;
}
if (_publicKeys.count() > 0) {
// we _must_ be authenticated if the publicKeys are there
return true;
}
// otherwise, we have a passphrase but no keys, so we have to check
auto publicKey = readPublicKey(keyFilePath().toStdString().c_str());
if (publicKey.size() > 0) {
if (auto key = readPrivateKey(keyFilePath().toStdString().c_str())) {
RSA_free(key);
// be sure to add the public key so we don't do this over and over
_publicKeys.push_back(publicKey.toBase64());
return true;
}
}
return false;
}
bool Wallet::createIfNeeded() { bool Wallet::createIfNeeded() {
if (_publicKeys.count() > 0) return false; if (_publicKeys.count() > 0) return false;
@ -464,7 +537,9 @@ void Wallet::getSecurityImage() {
} }
// decrypt and return // decrypt and return
if (decryptFile(imageFilePath(), &data, &dataLen)) { QString filePath(imageFilePath());
QFileInfo fileInfo(filePath);
if (fileInfo.exists() && decryptFile(filePath, &data, &dataLen)) {
// create the pixmap // create the pixmap
_securityImage = new QPixmap(); _securityImage = new QPixmap();
_securityImage->loadFromData(data, dataLen, "jpg"); _securityImage->loadFromData(data, dataLen, "jpg");
@ -488,3 +563,51 @@ void Wallet::sendKeyFilePathIfExists() {
emit keyFilePathIfExistsResult(""); emit keyFilePathIfExistsResult("");
} }
} }
void Wallet::reset() {
_publicKeys.clear();
delete _securityImage;
_securityImage = nullptr;
// tell the provider we got nothing
updateImageProvider();
delete _passphrase;
// for now we need to maintain the hard-coded passphrase.
// FIXME: remove this line as part of wiring up the passphrase
// and probably set it to nullptr
_passphrase = new QString("pwd");
QFile keyFile(keyFilePath());
QFile imageFile(imageFilePath());
keyFile.remove();
imageFile.remove();
}
bool Wallet::changePassphrase(const QString& newPassphrase) {
qCDebug(commerce) << "changing passphrase";
RSA* keys = readKeys(keyFilePath().toStdString().c_str());
if (keys) {
// we read successfully, so now write to a new temp file
// save old passphrase just in case
// TODO: force re-enter?
QString oldPassphrase = *_passphrase;
setPassphrase(newPassphrase);
QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp"));
if (writeKeys(tempFileName.toStdString().c_str(), keys)) {
// ok, now move the temp file to the correct spot
QFile(QString(keyFilePath())).remove();
QFile(tempFileName).rename(QString(keyFilePath()));
qCDebug(commerce) << "passphrase changed successfully";
return true;
} else {
qCDebug(commerce) << "couldn't write keys";
QFile(tempFileName).remove();
setPassphrase(oldPassphrase);
return false;
}
}
qCDebug(commerce) << "couldn't read keys";
return false;
}

View file

@ -39,16 +39,21 @@ public:
void setPassphrase(const QString& passphrase); void setPassphrase(const QString& passphrase);
QString* getPassphrase() { return _passphrase; } QString* getPassphrase() { return _passphrase; }
bool getPassphraseIsCached() { return !(_passphrase->isEmpty()); }
bool walletIsAuthenticatedWithPassphrase();
bool changePassphrase(const QString& newPassphrase);
void reset();
signals: signals:
void securityImageResult(bool exists) ; void securityImageResult(bool exists);
void keyFilePathIfExistsResult(const QString& path); void keyFilePathIfExistsResult(const QString& path);
private: private:
QStringList _publicKeys{}; QStringList _publicKeys{};
QPixmap* _securityImage { nullptr }; QPixmap* _securityImage { nullptr };
QByteArray _salt {"iamsalt!"}; QByteArray _salt {"iamsalt!"};
QString* _passphrase { new QString("pwd") }; QString* _passphrase { new QString("") };
void updateImageProvider(); void updateImageProvider();
bool encryptFile(const QString& inputFilePath, const QString& outputFilePath); bool encryptFile(const QString& inputFilePath, const QString& outputFilePath);

View file

@ -18,6 +18,8 @@ AccountScriptingInterface* AccountScriptingInterface::getInstance() {
auto accountManager = DependencyManager::get<AccountManager>(); auto accountManager = DependencyManager::get<AccountManager>();
QObject::connect(accountManager.data(), &AccountManager::profileChanged, QObject::connect(accountManager.data(), &AccountManager::profileChanged,
&sharedInstance, &AccountScriptingInterface::usernameChanged); &sharedInstance, &AccountScriptingInterface::usernameChanged);
QObject::connect(accountManager.data(), &AccountManager::usernameChanged,
&sharedInstance, &AccountScriptingInterface::onUsernameChanged);
return &sharedInstance; return &sharedInstance;
} }
@ -31,6 +33,21 @@ bool AccountScriptingInterface::checkAndSignalForAccessToken() {
return accountManager->checkAndSignalForAccessToken(); return accountManager->checkAndSignalForAccessToken();
} }
void AccountScriptingInterface::logOut() {
auto accountManager = DependencyManager::get<AccountManager>();
return accountManager->logout();
}
AccountScriptingInterface::AccountScriptingInterface(QObject *parent): QObject(parent) {
m_loggedIn = isLoggedIn();
emit loggedInChanged(m_loggedIn);
}
void AccountScriptingInterface::onUsernameChanged(QString username) {
m_loggedIn = (username != QString());
emit loggedInChanged(m_loggedIn);
}
QString AccountScriptingInterface::getUsername() { QString AccountScriptingInterface::getUsername() {
auto accountManager = DependencyManager::get<AccountManager>(); auto accountManager = DependencyManager::get<AccountManager>();
if (accountManager->isLoggedIn()) { if (accountManager->isLoggedIn()) {

View file

@ -18,6 +18,7 @@ class AccountScriptingInterface : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged) Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
Q_PROPERTY(bool loggedIn READ loggedIn NOTIFY loggedInChanged)
/**jsdoc /**jsdoc
* @namespace Account * @namespace Account
@ -32,6 +33,7 @@ signals:
* @return {Signal} * @return {Signal}
*/ */
void usernameChanged(); void usernameChanged();
void loggedInChanged(bool loggedIn);
public slots: public slots:
static AccountScriptingInterface* getInstance(); static AccountScriptingInterface* getInstance();
@ -50,6 +52,20 @@ public slots:
*/ */
bool isLoggedIn(); bool isLoggedIn();
bool checkAndSignalForAccessToken(); bool checkAndSignalForAccessToken();
void logOut();
public:
AccountScriptingInterface(QObject* parent = nullptr);
bool loggedIn() const {
return m_loggedIn;
}
private slots:
void onUsernameChanged(QString username);
private:
bool m_loggedIn { false };
}; };
#endif // hifi_AccountScriptingInterface_h #endif // hifi_AccountScriptingInterface_h

View file

@ -33,7 +33,12 @@ void DialogsManagerScriptingInterface::showAddressBar() {
void DialogsManagerScriptingInterface::hideAddressBar() { void DialogsManagerScriptingInterface::hideAddressBar() {
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(), QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
"hideAddressBar", Qt::QueuedConnection); "hideAddressBar", Qt::QueuedConnection);
}
void DialogsManagerScriptingInterface::showLoginDialog() {
QMetaObject::invokeMethod(DependencyManager::get<DialogsManager>().data(),
"showLoginDialog", Qt::QueuedConnection);
} }
void DialogsManagerScriptingInterface::showFeed() { void DialogsManagerScriptingInterface::showFeed() {

View file

@ -24,6 +24,7 @@ public:
public slots: public slots:
void showAddressBar(); void showAddressBar();
void hideAddressBar(); void hideAddressBar();
void showLoginDialog();
signals: signals:
void addressBarShown(bool visible); void addressBarShown(bool visible);

View file

@ -0,0 +1,195 @@
//
// SelectionScriptingInterface.cpp
// interface/src/scripting
//
// Created by Zach Fox on 2017-08-22.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "SelectionScriptingInterface.h"
#include <QDebug>
#include "Application.h"
GameplayObjects::GameplayObjects() {
}
bool GameplayObjects::addToGameplayObjects(const QUuid& avatarID) {
containsData = true;
_avatarIDs.push_back(avatarID);
return true;
}
bool GameplayObjects::removeFromGameplayObjects(const QUuid& avatarID) {
_avatarIDs.erase(std::remove(_avatarIDs.begin(), _avatarIDs.end(), avatarID), _avatarIDs.end());
return true;
}
bool GameplayObjects::addToGameplayObjects(const EntityItemID& entityID) {
containsData = true;
_entityIDs.push_back(entityID);
return true;
}
bool GameplayObjects::removeFromGameplayObjects(const EntityItemID& entityID) {
_entityIDs.erase(std::remove(_entityIDs.begin(), _entityIDs.end(), entityID), _entityIDs.end());
return true;
}
bool GameplayObjects::addToGameplayObjects(const OverlayID& overlayID) {
containsData = true;
_overlayIDs.push_back(overlayID);
return true;
}
bool GameplayObjects::removeFromGameplayObjects(const OverlayID& overlayID) {
_overlayIDs.erase(std::remove(_overlayIDs.begin(), _overlayIDs.end(), overlayID), _overlayIDs.end());
return true;
}
SelectionScriptingInterface::SelectionScriptingInterface() {
}
bool SelectionScriptingInterface::addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) {
if (itemType == "avatar") {
return addToGameplayObjects(listName, (QUuid)id);
} else if (itemType == "entity") {
return addToGameplayObjects(listName, (EntityItemID)id);
} else if (itemType == "overlay") {
return addToGameplayObjects(listName, (OverlayID)id);
}
return false;
}
bool SelectionScriptingInterface::removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id) {
if (itemType == "avatar") {
return removeFromGameplayObjects(listName, (QUuid)id);
} else if (itemType == "entity") {
return removeFromGameplayObjects(listName, (EntityItemID)id);
} else if (itemType == "overlay") {
return removeFromGameplayObjects(listName, (OverlayID)id);
}
return false;
}
template <class T> bool SelectionScriptingInterface::addToGameplayObjects(const QString& listName, T idToAdd) {
GameplayObjects currentList = _selectedItemsListMap.value(listName);
currentList.addToGameplayObjects(idToAdd);
_selectedItemsListMap.insert(listName, currentList);
emit selectedItemsListChanged(listName);
return true;
}
template <class T> bool SelectionScriptingInterface::removeFromGameplayObjects(const QString& listName, T idToRemove) {
GameplayObjects currentList = _selectedItemsListMap.value(listName);
if (currentList.getContainsData()) {
currentList.removeFromGameplayObjects(idToRemove);
_selectedItemsListMap.insert(listName, currentList);
emit selectedItemsListChanged(listName);
return true;
} else {
return false;
}
}
//
// END HANDLING GENERIC ITEMS
//
GameplayObjects SelectionScriptingInterface::getList(const QString& listName) {
return _selectedItemsListMap.value(listName);
}
void SelectionScriptingInterface::printList(const QString& listName) {
GameplayObjects currentList = _selectedItemsListMap.value(listName);
if (currentList.getContainsData()) {
qDebug() << "Avatar IDs:";
for (auto i : currentList.getAvatarIDs()) {
qDebug() << i << ';';
}
qDebug() << "";
qDebug() << "Entity IDs:";
for (auto j : currentList.getEntityIDs()) {
qDebug() << j << ';';
}
qDebug() << "";
qDebug() << "Overlay IDs:";
for (auto k : currentList.getOverlayIDs()) {
qDebug() << k << ';';
}
qDebug() << "";
} else {
qDebug() << "List named" << listName << "doesn't exist.";
}
}
bool SelectionScriptingInterface::removeListFromMap(const QString& listName) {
if (_selectedItemsListMap.remove(listName)) {
emit selectedItemsListChanged(listName);
return true;
} else {
return false;
}
}
SelectionToSceneHandler::SelectionToSceneHandler() {
}
void SelectionToSceneHandler::initialize(const QString& listName) {
_listName = listName;
}
void SelectionToSceneHandler::selectedItemsListChanged(const QString& listName) {
if (listName == _listName) {
updateSceneFromSelectedList();
}
}
void SelectionToSceneHandler::updateSceneFromSelectedList() {
auto mainScene = qApp->getMain3DScene();
if (mainScene) {
GameplayObjects thisList = DependencyManager::get<SelectionScriptingInterface>()->getList(_listName);
render::Transaction transaction;
render::ItemIDs finalList;
render::ItemID currentID;
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
auto& overlays = qApp->getOverlays();
for (QUuid& currentAvatarID : thisList.getAvatarIDs()) {
auto avatar = std::static_pointer_cast<Avatar>(DependencyManager::get<AvatarManager>()->getAvatarBySessionID(currentAvatarID));
if (avatar) {
currentID = avatar->getRenderItemID();
if (currentID != render::Item::INVALID_ITEM_ID) {
finalList.push_back(currentID);
}
}
}
for (EntityItemID& currentEntityID : thisList.getEntityIDs()) {
currentID = entityTreeRenderer->renderableIdForEntityId(currentEntityID);
if (currentID != render::Item::INVALID_ITEM_ID) {
finalList.push_back(currentID);
}
}
for (OverlayID& currentOverlayID : thisList.getOverlayIDs()) {
auto overlay = overlays.getOverlay(currentOverlayID);
if (overlay != NULL) {
currentID = overlay->getRenderItemID();
if (currentID != render::Item::INVALID_ITEM_ID) {
finalList.push_back(currentID);
}
}
}
render::Selection selection(_listName.toStdString(), finalList);
transaction.resetSelection(selection);
mainScene->enqueueTransaction(transaction);
} else {
qWarning() << "SelectionToSceneHandler::updateRendererSelectedList(), Unexpected null scene, possibly during application shutdown";
}
}

View file

@ -0,0 +1,91 @@
// SelectionScriptingInterface.h
// interface/src/scripting
//
// Created by Zach Fox on 2017-08-22.
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_SelectionScriptingInterface_h
#define hifi_SelectionScriptingInterface_h
#include <QtCore/QObject>
#include <QtCore/QMap>
#include <DependencyManager.h>
#include <AbstractViewStateInterface.h>
#include "RenderableEntityItem.h"
#include "ui/overlays/Overlay.h"
#include <avatar/AvatarManager.h>
class GameplayObjects {
public:
GameplayObjects();
bool getContainsData() { return containsData; }
std::vector<QUuid> getAvatarIDs() { return _avatarIDs; }
bool addToGameplayObjects(const QUuid& avatarID);
bool removeFromGameplayObjects(const QUuid& avatarID);
std::vector<EntityItemID> getEntityIDs() { return _entityIDs; }
bool addToGameplayObjects(const EntityItemID& entityID);
bool removeFromGameplayObjects(const EntityItemID& entityID);
std::vector<OverlayID> getOverlayIDs() { return _overlayIDs; }
bool addToGameplayObjects(const OverlayID& overlayID);
bool removeFromGameplayObjects(const OverlayID& overlayID);
private:
bool containsData { false };
std::vector<QUuid> _avatarIDs;
std::vector<EntityItemID> _entityIDs;
std::vector<OverlayID> _overlayIDs;
};
class SelectionScriptingInterface : public QObject, public Dependency {
Q_OBJECT
public:
SelectionScriptingInterface();
GameplayObjects getList(const QString& listName);
Q_INVOKABLE void printList(const QString& listName);
Q_INVOKABLE bool removeListFromMap(const QString& listName);
Q_INVOKABLE bool addToSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id);
Q_INVOKABLE bool removeFromSelectedItemsList(const QString& listName, const QString& itemType, const QUuid& id);
signals:
void selectedItemsListChanged(const QString& listName);
private:
QMap<QString, GameplayObjects> _selectedItemsListMap;
template <class T> bool addToGameplayObjects(const QString& listName, T idToAdd);
template <class T> bool removeFromGameplayObjects(const QString& listName, T idToRemove);
};
class SelectionToSceneHandler : public QObject {
Q_OBJECT
public:
SelectionToSceneHandler();
void initialize(const QString& listName);
void updateSceneFromSelectedList();
public slots:
void selectedItemsListChanged(const QString& listName);
private:
QString _listName { "" };
};
#endif // hifi_SelectionScriptingInterface_h

View file

@ -28,6 +28,9 @@ ContextOverlayInterface::ContextOverlayInterface() {
_entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); _entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
_hmdScriptingInterface = DependencyManager::get<HMDScriptingInterface>(); _hmdScriptingInterface = DependencyManager::get<HMDScriptingInterface>();
_tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); _tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
_selectionScriptingInterface = DependencyManager::get<SelectionScriptingInterface>();
_selectionToSceneHandler.initialize("contextOverlayHighlightList");
_entityPropertyFlags += PROP_POSITION; _entityPropertyFlags += PROP_POSITION;
_entityPropertyFlags += PROP_ROTATION; _entityPropertyFlags += PROP_ROTATION;
@ -58,6 +61,8 @@ ContextOverlayInterface::ContextOverlayInterface() {
}); });
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data(); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>().data();
connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity); connect(entityScriptingInterface, &EntityScriptingInterface::deletingEntity, this, &ContextOverlayInterface::deletingEntity);
connect(_selectionScriptingInterface.data(), &SelectionScriptingInterface::selectedItemsListChanged, &_selectionToSceneHandler, &SelectionToSceneHandler::selectedItemsListChanged);
} }
static const uint32_t LEFT_HAND_HW_ID = 1; static const uint32_t LEFT_HAND_HW_ID = 1;
@ -261,25 +266,11 @@ void ContextOverlayInterface::openMarketplace() {
} }
void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) { void ContextOverlayInterface::enableEntityHighlight(const EntityItemID& entityItemID) {
auto entityTree = qApp->getEntities()->getTree(); _selectionScriptingInterface->addToSelectedItemsList("contextOverlayHighlightList", "entity", entityItemID);
entityTree->withReadLock([&] {
auto entityItem = entityTree->findEntityByEntityItemID(entityItemID);
if ((entityItem != NULL) && !entityItem->getShouldHighlight()) {
qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'true' for Entity ID:" << entityItemID;
entityItem->setShouldHighlight(true);
}
});
} }
void ContextOverlayInterface::disableEntityHighlight(const EntityItemID& entityItemID) { void ContextOverlayInterface::disableEntityHighlight(const EntityItemID& entityItemID) {
auto entityTree = qApp->getEntities()->getTree(); _selectionScriptingInterface->removeFromSelectedItemsList("contextOverlayHighlightList", "entity", entityItemID);
entityTree->withReadLock([&] {
auto entityItem = entityTree->findEntityByEntityItemID(entityItemID);
if ((entityItem != NULL) && entityItem->getShouldHighlight()) {
qCDebug(context_overlay) << "Setting 'shouldHighlight' to 'false' for Entity ID:" << entityItemID;
entityItem->setShouldHighlight(false);
}
});
} }
void ContextOverlayInterface::deletingEntity(const EntityItemID& entityID) { void ContextOverlayInterface::deletingEntity(const EntityItemID& entityID) {

View file

@ -25,6 +25,7 @@
#include "ui/overlays/Image3DOverlay.h" #include "ui/overlays/Image3DOverlay.h"
#include "ui/overlays/Overlays.h" #include "ui/overlays/Overlays.h"
#include "scripting/HMDScriptingInterface.h" #include "scripting/HMDScriptingInterface.h"
#include "scripting/SelectionScriptingInterface.h"
#include "EntityTree.h" #include "EntityTree.h"
#include "ContextOverlayLogging.h" #include "ContextOverlayLogging.h"
@ -42,6 +43,7 @@ class ContextOverlayInterface : public QObject, public Dependency {
EntityPropertyFlags _entityPropertyFlags; EntityPropertyFlags _entityPropertyFlags;
QSharedPointer<HMDScriptingInterface> _hmdScriptingInterface; QSharedPointer<HMDScriptingInterface> _hmdScriptingInterface;
QSharedPointer<TabletScriptingInterface> _tabletScriptingInterface; QSharedPointer<TabletScriptingInterface> _tabletScriptingInterface;
QSharedPointer<SelectionScriptingInterface> _selectionScriptingInterface;
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID }; OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr }; std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
public: public:
@ -81,6 +83,8 @@ private:
void disableEntityHighlight(const EntityItemID& entityItemID); void disableEntityHighlight(const EntityItemID& entityItemID);
void deletingEntity(const EntityItemID& entityItemID); void deletingEntity(const EntityItemID& entityItemID);
SelectionToSceneHandler _selectionToSceneHandler;
}; };
#endif // hifi_ContextOverlayInterface_h #endif // hifi_ContextOverlayInterface_h

View file

@ -242,6 +242,7 @@ public:
void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene); void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene); void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene);
bool isInScene() const { return render::Item::isValidID(_renderItemID); } bool isInScene() const { return render::Item::isValidID(_renderItemID); }
render::ItemID getRenderItemID() { return _renderItemID; }
bool isMoving() const { return _moving; } bool isMoving() const { return _moving; }
void setPhysicsCallback(AvatarPhysicsCallback cb); void setPhysicsCallback(AvatarPhysicsCallback cb);

View file

@ -147,6 +147,7 @@ public slots:
void setDisplayModelBounds(bool value) { _displayModelBounds = value; } void setDisplayModelBounds(bool value) { _displayModelBounds = value; }
void setPrecisionPicking(bool value) { _setPrecisionPickingOperator(_mouseRayPickID, value); } void setPrecisionPicking(bool value) { _setPrecisionPickingOperator(_mouseRayPickID, value); }
EntityRendererPointer renderableForEntityId(const EntityItemID& id) const; EntityRendererPointer renderableForEntityId(const EntityItemID& id) const;
render::ItemID renderableIdForEntityId(const EntityItemID& id) const;
protected: protected:
virtual OctreePointer createTree() override { virtual OctreePointer createTree() override {
@ -156,7 +157,6 @@ protected:
} }
private: private:
render::ItemID renderableIdForEntityId(const EntityItemID& id) const;
EntityRendererPointer renderableForEntity(const EntityItemPointer& entity) const { return renderableForEntityId(entity->getID()); } EntityRendererPointer renderableForEntity(const EntityItemPointer& entity) const { return renderableForEntityId(entity->getID()); }
render::ItemID renderableIdForEntity(const EntityItemPointer& entity) const { return renderableIdForEntityId(entity->getID()); } render::ItemID renderableIdForEntity(const EntityItemPointer& entity) const { return renderableIdForEntityId(entity->getID()); }

View file

@ -910,6 +910,8 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
auto& fbxJoints = _animation->getGeometry().joints; auto& fbxJoints = _animation->getGeometry().joints;
auto& originalFbxJoints = _model->getFBXGeometry().joints;
bool allowTranslation = entity->getAnimationAllowTranslation();
int frameCount = frames.size(); int frameCount = frames.size();
if (frameCount <= 0) { if (frameCount <= 0) {
return; return;
@ -952,7 +954,9 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
int index = _jointMapping[j]; int index = _jointMapping[j];
if (index >= 0) { if (index >= 0) {
glm::mat4 translationMat; glm::mat4 translationMat;
if (index < translations.size()) { if (!allowTranslation){
translationMat = glm::translate(originalFbxJoints[index].translation);
} else if (index < translations.size()) {
translationMat = glm::translate(translations[index]); translationMat = glm::translate(translations[index]);
} }
glm::mat4 rotationMat; glm::mat4 rotationMat;
@ -1080,7 +1084,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
} }
_marketplaceEntity = entity->getMarketplaceID().length() != 0; _marketplaceEntity = entity->getMarketplaceID().length() != 0;
_shouldHighlight = entity->getShouldHighlight();
_animating = entity->isAnimatingSomething(); _animating = entity->isAnimatingSomething();
withWriteLock([&] { withWriteLock([&] {
@ -1207,17 +1210,6 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
model = _model; model = _model;
}); });
// this simple logic should say we set showingEntityHighlight to true whenever we are in marketplace mode and we have a marketplace id, or
// whenever we are not set to none and shouldHighlight is true.
bool showingEntityHighlight = ((bool)(args->_outlineFlags & (int)RenderArgs::RENDER_OUTLINE_MARKETPLACE_MODE) && _marketplaceEntity != 0) ||
(args->_outlineFlags != RenderArgs::RENDER_OUTLINE_NONE && _shouldHighlight);
if (showingEntityHighlight) {
static glm::vec4 yellowColor(1.0f, 1.0f, 0.0f, 1.0f);
gpu::Batch& batch = *args->_batch;
batch.setModelTransform(_modelTransform); // we want to include the scale as well
DependencyManager::get<GeometryCache>()->renderWireCubeInstance(args, batch, yellowColor);
}
if (_model && _model->didVisualGeometryRequestFail()) { if (_model && _model->didVisualGeometryRequestFail()) {
static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;

View file

@ -33,6 +33,7 @@ bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, Animation, animation, Running, running); COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, Animation, animation, Running, running);
@ -46,6 +47,7 @@ void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desire
void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, url, QString, setURL); COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, url, QString, setURL);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, allowTranslation, bool, setAllowTranslation);
// legacy property support // legacy property support
COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationURL, QString, setURL, getURL); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationURL, QString, setURL, getURL);
@ -67,6 +69,7 @@ void AnimationPropertyGroup::copyFromScriptValue(const QScriptValue& object, boo
void AnimationPropertyGroup::merge(const AnimationPropertyGroup& other) { void AnimationPropertyGroup::merge(const AnimationPropertyGroup& other) {
COPY_PROPERTY_IF_CHANGED(url); COPY_PROPERTY_IF_CHANGED(url);
COPY_PROPERTY_IF_CHANGED(allowTranslation);
COPY_PROPERTY_IF_CHANGED(fps); COPY_PROPERTY_IF_CHANGED(fps);
COPY_PROPERTY_IF_CHANGED(currentFrame); COPY_PROPERTY_IF_CHANGED(currentFrame);
COPY_PROPERTY_IF_CHANGED(running); COPY_PROPERTY_IF_CHANGED(running);
@ -88,6 +91,7 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
float lastFrame = getLastFrame(); float lastFrame = getLastFrame();
bool loop = getLoop(); bool loop = getLoop();
bool hold = getHold(); bool hold = getHold();
bool allowTranslation = getAllowTranslation();
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
QJsonObject settingsAsJsonObject = settingsAsJson.object(); QJsonObject settingsAsJsonObject = settingsAsJson.object();
@ -122,6 +126,11 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
running = settingsMap["hold"].toBool(); running = settingsMap["hold"].toBool();
} }
if (settingsMap.contains("allowTranslation")) {
allowTranslation = settingsMap["allowTranslation"].toBool();
}
setAllowTranslation(allowTranslation);
setFPS(fps); setFPS(fps);
setCurrentFrame(currentFrame); setCurrentFrame(currentFrame);
setRunning(running); setRunning(running);
@ -137,6 +146,7 @@ void AnimationPropertyGroup::debugDump() const {
qCDebug(entities) << " url:" << getURL() << " has changed:" << urlChanged(); qCDebug(entities) << " url:" << getURL() << " has changed:" << urlChanged();
qCDebug(entities) << " fps:" << getFPS() << " has changed:" << fpsChanged(); qCDebug(entities) << " fps:" << getFPS() << " has changed:" << fpsChanged();
qCDebug(entities) << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged(); qCDebug(entities) << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged();
qCDebug(entities) << "allowTranslation:" << getAllowTranslation() << " has changed:" << allowTranslationChanged();
} }
void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) { void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
@ -149,6 +159,9 @@ void AnimationPropertyGroup::listChangedProperties(QList<QString>& out) {
if (currentFrameChanged()) { if (currentFrameChanged()) {
out << "animation-currentFrame"; out << "animation-currentFrame";
} }
if (allowTranslationChanged()) {
out << "animation-allowTranslation";
}
} }
@ -162,6 +175,7 @@ bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
bool successPropertyFits = true; bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, getAllowTranslation());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning());
@ -181,6 +195,7 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
bool somethingChanged = false; bool somethingChanged = false;
READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL); READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL);
READ_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, bool, setAllowTranslation);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS); READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame);
@ -198,7 +213,8 @@ bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyF
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold); DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation);
processedBytes += bytesRead; processedBytes += bytesRead;
Q_UNUSED(somethingChanged); Q_UNUSED(somethingChanged);
@ -215,6 +231,7 @@ void AnimationPropertyGroup::markAllChanged() {
_firstFrameChanged = true; _firstFrameChanged = true;
_lastFrameChanged = true; _lastFrameChanged = true;
_holdChanged = true; _holdChanged = true;
_allowTranslationChanged = true;
} }
EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const { EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const {
@ -228,12 +245,14 @@ EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold); CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_ALLOW_TRANSLATION, allowTranslation);
return changedProperties; return changedProperties;
} }
void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) const { void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) const {
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, URL, getURL); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, URL, getURL);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, AllowTranslation, getAllowTranslation);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FPS, getFPS); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FPS, getFPS);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, CurrentFrame, getCurrentFrame); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, CurrentFrame, getCurrentFrame);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Running, getRunning); COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Running, getRunning);
@ -247,6 +266,7 @@ bool AnimationPropertyGroup::setProperties(const EntityItemProperties& propertie
bool somethingChanged = false; bool somethingChanged = false;
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, URL, url, setURL); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, URL, url, setURL);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, AllowTranslation, allowTranslation, setAllowTranslation);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FPS, fps, setFPS); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FPS, fps, setFPS);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, CurrentFrame, currentFrame, setCurrentFrame); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, CurrentFrame, currentFrame, setCurrentFrame);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Running, running, setRunning); SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Running, running, setRunning);
@ -268,6 +288,7 @@ EntityPropertyFlags AnimationPropertyGroup::getEntityProperties(EncodeBitstreamP
requestedProperties += PROP_ANIMATION_FIRST_FRAME; requestedProperties += PROP_ANIMATION_FIRST_FRAME;
requestedProperties += PROP_ANIMATION_LAST_FRAME; requestedProperties += PROP_ANIMATION_LAST_FRAME;
requestedProperties += PROP_ANIMATION_HOLD; requestedProperties += PROP_ANIMATION_HOLD;
requestedProperties += PROP_ANIMATION_ALLOW_TRANSLATION;
return requestedProperties; return requestedProperties;
} }
@ -283,6 +304,7 @@ void AnimationPropertyGroup::appendSubclassData(OctreePacketData* packetData, En
bool successPropertyFits = true; bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, getAllowTranslation());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning());
@ -301,6 +323,7 @@ int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char
const unsigned char* dataAt = data; const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL); READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL);
READ_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, bool, setAllowTranslation);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS); READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS);
READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame); READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame);
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setRunning); READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setRunning);

View file

@ -85,6 +85,7 @@ public:
DEFINE_PROPERTY(PROP_ANIMATION_FIRST_FRAME, FirstFrame, firstFrame, float, 0.0f); // was animationSettings.firstFrame DEFINE_PROPERTY(PROP_ANIMATION_FIRST_FRAME, FirstFrame, firstFrame, float, 0.0f); // was animationSettings.firstFrame
DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame
DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold
DEFINE_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation, allowTranslation, bool, true);
protected: protected:
friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b); friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);

View file

@ -94,7 +94,6 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_LOCKED; requestedProperties += PROP_LOCKED;
requestedProperties += PROP_USER_DATA; requestedProperties += PROP_USER_DATA;
requestedProperties += PROP_MARKETPLACE_ID; requestedProperties += PROP_MARKETPLACE_ID;
requestedProperties += PROP_SHOULD_HIGHLIGHT;
requestedProperties += PROP_NAME; requestedProperties += PROP_NAME;
requestedProperties += PROP_HREF; requestedProperties += PROP_HREF;
requestedProperties += PROP_DESCRIPTION; requestedProperties += PROP_DESCRIPTION;
@ -240,7 +239,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData());
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID()); APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, getShouldHighlight());
APPEND_ENTITY_PROPERTY(PROP_NAME, getName()); APPEND_ENTITY_PROPERTY(PROP_NAME, getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL());
APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); APPEND_ENTITY_PROPERTY(PROP_HREF, getHref());
@ -792,10 +790,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
} }
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT) {
READ_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, bool, setShouldHighlight);
}
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
@ -2772,20 +2766,6 @@ void EntityItem::setMarketplaceID(const QString& value) {
}); });
} }
bool EntityItem::getShouldHighlight() const {
bool result;
withReadLock([&] {
result = _shouldHighlight;
});
return result;
}
void EntityItem::setShouldHighlight(const bool value) {
withWriteLock([&] {
_shouldHighlight = value;
});
}
uint32_t EntityItem::getDirtyFlags() const { uint32_t EntityItem::getDirtyFlags() const {
uint32_t result; uint32_t result;
withReadLock([&] { withReadLock([&] {

View file

@ -289,7 +289,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID); CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
CHECK_PROPERTY_CHANGE(PROP_SHOULD_HIGHLIGHT, shouldHighlight);
CHECK_PROPERTY_CHANGE(PROP_NAME, name); CHECK_PROPERTY_CHANGE(PROP_NAME, name);
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode); CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
@ -407,7 +406,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MARKETPLACE_ID, marketplaceID);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHOULD_HIGHLIGHT, shouldHighlight);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
@ -984,7 +982,6 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float); ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float);
ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float); ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); ADD_PROPERTY_TO_MAP(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
ADD_PROPERTY_TO_MAP(PROP_SHOULD_HIGHLIGHT, ShouldHighlight, shouldHighlight, bool);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float); ADD_PROPERTY_TO_MAP(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
@ -1036,6 +1033,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold);
ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color); ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color);
ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_URL, Skybox, skybox, URL, url); ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_URL, Skybox, skybox, URL, url);
@ -1337,7 +1335,6 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape()); APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape());
} }
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID()); APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_SHOULD_HIGHLIGHT, properties.getShouldHighlight());
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
@ -1636,7 +1633,6 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
} }
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHOULD_HIGHLIGHT, bool, setShouldHighlight);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
@ -1751,7 +1747,6 @@ void EntityItemProperties::markAllChanged() {
//_alphaFinishChanged = true; //_alphaFinishChanged = true;
_marketplaceIDChanged = true; _marketplaceIDChanged = true;
_shouldHighlightChanged = true;
_keyLight.markAllChanged(); _keyLight.markAllChanged();

View file

@ -171,7 +171,6 @@ public:
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, particle::DEFAULT_RADIUS_FINISH); DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, particle::DEFAULT_RADIUS_FINISH);
DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, particle::DEFAULT_EMITTER_SHOULD_TRAIL); DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, particle::DEFAULT_EMITTER_SHOULD_TRAIL);
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID); DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID);
DEFINE_PROPERTY_REF(PROP_SHOULD_HIGHLIGHT, ShouldHighlight, shouldHighlight, bool, ENTITY_ITEM_DEFAULT_SHOULD_HIGHLIGHT);
DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup); DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup);
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE); DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE);
DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray, PolyVoxEntityItem::DEFAULT_VOXEL_DATA); DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray, PolyVoxEntityItem::DEFAULT_VOXEL_DATA);

View file

@ -27,7 +27,6 @@ const glm::vec3 ENTITY_ITEM_HALF_VEC3 = glm::vec3(0.5f);
const bool ENTITY_ITEM_DEFAULT_LOCKED = false; const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString(""); const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
const bool ENTITY_ITEM_DEFAULT_SHOULD_HIGHLIGHT = false;
const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid(); const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;

View file

@ -40,6 +40,7 @@ enum EntityPropertyList {
PROP_ANIMATION_FPS, PROP_ANIMATION_FPS,
PROP_ANIMATION_FRAME_INDEX, PROP_ANIMATION_FRAME_INDEX,
PROP_ANIMATION_PLAYING, PROP_ANIMATION_PLAYING,
PROP_ANIMATION_ALLOW_TRANSLATION,
// these properties are supported by the EntityItem base class // these properties are supported by the EntityItem base class
PROP_REGISTRATION_POINT, PROP_REGISTRATION_POINT,
@ -78,7 +79,6 @@ enum EntityPropertyList {
PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities PROP_COMPOUND_SHAPE_URL, // used by Model + zones entities
PROP_MARKETPLACE_ID, // all entities PROP_MARKETPLACE_ID, // all entities
PROP_SHOULD_HIGHLIGHT, // all entities
PROP_ACCELERATION, // all entities PROP_ACCELERATION, // all entities
PROP_SIMULATION_OWNER, // formerly known as PROP_SIMULATOR_ID PROP_SIMULATION_OWNER, // formerly known as PROP_SIMULATOR_ID
PROP_NAME, // all entities PROP_NAME, // all entities

View file

@ -330,6 +330,10 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
setAnimationHold(hold); setAnimationHold(hold);
} }
if (settingsMap.contains("allowTranslation")) {
bool allowTranslation = settingsMap["allowTranslation"].toBool();
setAnimationAllowTranslation(allowTranslation);
}
_dirtyFlags |= Simulation::DIRTY_UPDATEABLE; _dirtyFlags |= Simulation::DIRTY_UPDATEABLE;
} }

View file

@ -83,7 +83,10 @@ public:
void setAnimationCurrentFrame(float value); void setAnimationCurrentFrame(float value);
void setAnimationIsPlaying(bool value); void setAnimationIsPlaying(bool value);
void setAnimationFPS(float value); void setAnimationFPS(float value);
void setAnimationAllowTranslation(bool value) { _animationProperties.setAllowTranslation(value); };
bool getAnimationAllowTranslation() const { return _animationProperties.getAllowTranslation(); };
void setAnimationLoop(bool loop); void setAnimationLoop(bool loop);
bool getAnimationLoop() const; bool getAnimationLoop() const;

View file

@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit: case PacketType::EntityEdit:
case PacketType::EntityData: case PacketType::EntityData:
case PacketType::EntityPhysics: case PacketType::EntityPhysics:
return VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT; return VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES;
case PacketType::EntityQuery: case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree); return static_cast<PacketVersion>(EntityQueryPacketVersion::JSONFilterWithFamilyTree);
case PacketType::AvatarIdentity: case PacketType::AvatarIdentity:

View file

@ -259,6 +259,8 @@ const PacketVersion VERSION_ENTITIES_ZONE_FILTERS = 68;
const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69; const PacketVersion VERSION_ENTITIES_HINGE_CONSTRAINT = 69;
const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70; const PacketVersion VERSION_ENTITIES_BULLET_DYNAMICS = 70;
const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71; const PacketVersion VERSION_ENTITIES_HAS_SHOULD_HIGHLIGHT = 71;
const PacketVersion VERSION_ENTITIES_HAS_HIGHLIGHT_SCRIPTING_INTERFACE = 72;
const PacketVersion VERSION_ENTITIES_ANIMATION_ALLOW_TRANSLATION_PROPERTIES = 73;
enum class EntityQueryPacketVersion: PacketVersion { enum class EntityQueryPacketVersion: PacketVersion {
JSONFilter = 18, JSONFilter = 18,

View file

@ -92,6 +92,7 @@ void EntityMotionState::updateServerPhysicsVariables() {
Transform localTransform; Transform localTransform;
_entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity); _entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity);
_serverVariablesSet = true;
_serverPosition = localTransform.getTranslation(); _serverPosition = localTransform.getTranslation();
_serverRotation = localTransform.getRotation(); _serverRotation = localTransform.getRotation();
_serverAcceleration = _entity->getAcceleration(); _serverAcceleration = _entity->getAcceleration();
@ -99,18 +100,19 @@ void EntityMotionState::updateServerPhysicsVariables() {
} }
void EntityMotionState::handleDeactivation() { void EntityMotionState::handleDeactivation() {
// copy _server data to entity if (_serverVariablesSet) {
bool success; // copy _server data to entity
_entity->setPosition(_serverPosition, success, false); Transform localTransform = _entity->getLocalTransform();
_entity->setOrientation(_serverRotation, success, false); localTransform.setTranslation(_serverPosition);
_entity->setVelocity(ENTITY_ITEM_ZERO_VEC3); localTransform.setRotation(_serverRotation);
_entity->setAngularVelocity(ENTITY_ITEM_ZERO_VEC3); _entity->setLocalTransformAndVelocities(localTransform, ENTITY_ITEM_ZERO_VEC3, ENTITY_ITEM_ZERO_VEC3);
// and also to RigidBody // and also to RigidBody
btTransform worldTrans; btTransform worldTrans;
worldTrans.setOrigin(glmToBullet(_serverPosition)); worldTrans.setOrigin(glmToBullet(_entity->getPosition()));
worldTrans.setRotation(glmToBullet(_serverRotation)); worldTrans.setRotation(glmToBullet(_entity->getRotation()));
_body->setWorldTransform(worldTrans); _body->setWorldTransform(worldTrans);
// no need to update velocities... should already be zero // no need to update velocities... should already be zero
}
} }
// virtual // virtual
@ -339,6 +341,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
// if we've never checked before, our _lastStep will be 0, and we need to initialize our state // if we've never checked before, our _lastStep will be 0, and we need to initialize our state
if (_lastStep == 0) { if (_lastStep == 0) {
btTransform xform = _body->getWorldTransform(); btTransform xform = _body->getWorldTransform();
_serverVariablesSet = true;
_serverPosition = worldToLocal.transform(bulletToGLM(xform.getOrigin())); _serverPosition = worldToLocal.transform(bulletToGLM(xform.getOrigin()));
_serverRotation = worldToLocal.getRotation() * bulletToGLM(xform.getRotation()); _serverRotation = worldToLocal.getRotation() * bulletToGLM(xform.getRotation());
_serverVelocity = worldVelocityToLocal.transform(getBodyLinearVelocityGTSigma()); _serverVelocity = worldVelocityToLocal.transform(getBodyLinearVelocityGTSigma());

View file

@ -107,6 +107,7 @@ protected:
// Meanwhile we also keep a raw EntityItem* for internal stuff where the pointer is guaranteed valid. // Meanwhile we also keep a raw EntityItem* for internal stuff where the pointer is guaranteed valid.
EntityItem* _entity; EntityItem* _entity;
bool _serverVariablesSet { false };
glm::vec3 _serverPosition; // in simulation-frame (not world-frame) glm::vec3 _serverPosition; // in simulation-frame (not world-frame)
glm::quat _serverRotation; glm::quat _serverRotation;
glm::vec3 _serverVelocity; glm::vec3 _serverVelocity;

View file

@ -210,6 +210,10 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
} }
task.addJob<DebugZoneLighting>("DrawZoneStack", deferredFrameTransform); task.addJob<DebugZoneLighting>("DrawZoneStack", deferredFrameTransform);
// Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true
const auto selectedMetas = task.addJob<SelectItems>("PassTestSelection", metas, "contextOverlayHighlightList");
task.addJob<DrawBounds>("DrawSelectionBounds", selectedMetas);
} }
// AA job to be revisited // AA job to be revisited

View file

@ -63,12 +63,6 @@ namespace render {
public: public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE }; enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, SECONDARY_CAMERA_RENDER_MODE };
enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD }; enum DisplayMode { MONO, STEREO_MONITOR, STEREO_HMD };
enum OutlineFlags {
RENDER_OUTLINE_NONE = 0,
RENDER_OUTLINE_WIREFRAMES = 1,
RENDER_OUTLINE_MARKETPLACE_MODE = 2,
RENDER_OUTLINE_SHADER = 4
};
enum DebugFlags { enum DebugFlags {
RENDER_DEBUG_NONE = 0, RENDER_DEBUG_NONE = 0,
RENDER_DEBUG_HULLS = 1 RENDER_DEBUG_HULLS = 1
@ -115,7 +109,6 @@ namespace render {
int _boundaryLevelAdjust { 0 }; int _boundaryLevelAdjust { 0 };
RenderMode _renderMode { DEFAULT_RENDER_MODE }; RenderMode _renderMode { DEFAULT_RENDER_MODE };
DisplayMode _displayMode { MONO }; DisplayMode _displayMode { MONO };
OutlineFlags _outlineFlags{ RENDER_OUTLINE_NONE };
DebugFlags _debugFlags { RENDER_DEBUG_NONE }; DebugFlags _debugFlags { RENDER_DEBUG_NONE };
gpu::Batch* _batch = nullptr; gpu::Batch* _batch = nullptr;

View file

@ -827,10 +827,10 @@ AnimationDetails::AnimationDetails() :
} }
AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop, AnimationDetails::AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame) : bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame, bool allowTranslation) :
role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold), role(role), url(url), fps(fps), priority(priority), loop(loop), hold(hold),
startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame), startAutomatically(startAutomatically), firstFrame(firstFrame), lastFrame(lastFrame),
running(running), currentFrame(currentFrame) { running(running), currentFrame(currentFrame), allowTranslation(allowTranslation) {
} }
@ -847,6 +847,7 @@ QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const Animatio
obj.setProperty("lastFrame", details.lastFrame); obj.setProperty("lastFrame", details.lastFrame);
obj.setProperty("running", details.running); obj.setProperty("running", details.running);
obj.setProperty("currentFrame", details.currentFrame); obj.setProperty("currentFrame", details.currentFrame);
obj.setProperty("allowTranslation", details.allowTranslation);
return obj; return obj;
} }

View file

@ -197,7 +197,7 @@ class AnimationDetails {
public: public:
AnimationDetails(); AnimationDetails();
AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop, AnimationDetails(QString role, QUrl url, float fps, float priority, bool loop,
bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame); bool hold, bool startAutomatically, float firstFrame, float lastFrame, bool running, float currentFrame, bool allowTranslation);
QString role; QString role;
QUrl url; QUrl url;
@ -210,6 +210,7 @@ public:
float lastFrame; float lastFrame;
bool running; bool running;
float currentFrame; float currentFrame;
bool allowTranslation;
}; };
Q_DECLARE_METATYPE(AnimationDetails); Q_DECLARE_METATYPE(AnimationDetails);
QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event); QScriptValue animationDetailsToScriptValue(QScriptEngine* engine, const AnimationDetails& event);

View file

@ -731,7 +731,7 @@ void SpatiallyNestable::setScale(float value) {
} }
} }
const Transform SpatiallyNestable::getLocalTransform() const { Transform SpatiallyNestable::getLocalTransform() const {
Transform result; Transform result;
_transformLock.withReadLock([&] { _transformLock.withReadLock([&] {
result =_transform; result =_transform;

View file

@ -121,7 +121,7 @@ public:
virtual glm::vec3 getScale(int jointIndex) const; virtual glm::vec3 getScale(int jointIndex) const;
// object's parent's frame // object's parent's frame
virtual const Transform getLocalTransform() const; virtual Transform getLocalTransform() const;
virtual void setLocalTransform(const Transform& transform); virtual void setLocalTransform(const Transform& transform);
virtual glm::vec3 getLocalPosition() const; virtual glm::vec3 getLocalPosition() const;

View file

@ -18,10 +18,25 @@ const QString ImageProvider::PROVIDER_NAME = "security";
QReadWriteLock ImageProvider::_rwLock; QReadWriteLock ImageProvider::_rwLock;
QPixmap* ImageProvider::_securityImage = nullptr; QPixmap* ImageProvider::_securityImage = nullptr;
void ImageProvider::setSecurityImage(QPixmap* pixmap) { ImageProvider::~ImageProvider() {
QWriteLocker lock(&_rwLock);
if (_securityImage) {
delete _securityImage;
_securityImage = nullptr;
}
}
void ImageProvider::setSecurityImage(const QPixmap* pixmap) {
// no need to delete old one, that is managed by the wallet // no need to delete old one, that is managed by the wallet
QWriteLocker lock(&_rwLock); QWriteLocker lock(&_rwLock);
_securityImage = pixmap; if (_securityImage) {
delete _securityImage;
}
if (pixmap) {
_securityImage = new QPixmap(*pixmap);
} else {
_securityImage = nullptr;
}
} }
QPixmap ImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) { QPixmap ImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) {

View file

@ -20,10 +20,10 @@ public:
static const QString PROVIDER_NAME; static const QString PROVIDER_NAME;
ImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {} ImageProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) {}
virtual ~ImageProvider();
QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override; QPixmap requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) override;
void setSecurityImage(QPixmap* pixmap); void setSecurityImage(const QPixmap* pixmap);
protected: protected:
static QReadWriteLock _rwLock; static QReadWriteLock _rwLock;
static QPixmap* _securityImage; static QPixmap* _securityImage;

View file

@ -56,6 +56,7 @@
var isHmdPreviewDisabled = true; var isHmdPreviewDisabled = true;
function fromQml(message) { function fromQml(message) {
switch (message.method) { switch (message.method) {
case 'passphrasePopup_cancelClicked':
case 'walletSetup_cancelClicked': case 'walletSetup_cancelClicked':
case 'needsLogIn_cancelClicked': case 'needsLogIn_cancelClicked':
tablet.gotoHomeScreen(); tablet.gotoHomeScreen();
@ -70,6 +71,10 @@
case 'maybeEnableHmdPreview': case 'maybeEnableHmdPreview':
Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled); Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled);
break; break;
case 'walletReset':
onButtonClicked();
onButtonClicked();
break;
default: default:
print('Unrecognized message from QML:', JSON.stringify(message)); print('Unrecognized message from QML:', JSON.stringify(message));
} }

View file

@ -405,9 +405,11 @@ var toolBar = (function () {
} }
}); });
var createButtonIconRsrc = ((Entities.canRez() || Entities.canRezTmp()) ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON); var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp());
var createButtonIconRsrc = (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON);
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
activeButton = tablet.addButton({ activeButton = tablet.addButton({
captionColorOverride: hasRezPermissions ? "" : "#888888",
icon: createButtonIconRsrc, icon: createButtonIconRsrc,
activeIcon: "icons/tablet-icons/edit-a.svg", activeIcon: "icons/tablet-icons/edit-a.svg",
text: "CREATE", text: "CREATE",
@ -789,6 +791,7 @@ function handleDomainChange() {
var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp()); var hasRezPermissions = (Entities.canRez() || Entities.canRezTmp());
createButton.editProperties({ createButton.editProperties({
icon: (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON), icon: (hasRezPermissions ? CREATE_ENABLED_ICON : CREATE_DISABLED_ICON),
captionColorOverride: (hasRezPermissions ? "" : "#888888"),
}); });
} }

View file

@ -446,6 +446,10 @@
<input type="checkbox" id="property-model-animation-hold"> <input type="checkbox" id="property-model-animation-hold">
<label for="property-model-animation-hold">Animation hold</label> <label for="property-model-animation-hold">Animation hold</label>
</div> </div>
<div class="property checkbox indent">
<input type="checkbox" id="property-model-animation-allow-translation">
<label for="property-model-animation-allow-translation">Animation Allow Translation</label>
</div>
<div id="animation-fps" class="property number"> <div id="animation-fps" class="property number">
<label>Animation FPS</label> <label>Animation FPS</label>
<input type="number" id="property-model-animation-fps"> <input type="number" id="property-model-animation-fps">
@ -642,10 +646,6 @@
</div> </div>
</fieldset> </fieldset>
<fieldset id="polyvox" class="major"> <fieldset id="polyvox" class="major">
<legend class="section-header spatial-group poly-vox-section property xyz"> <legend class="section-header spatial-group poly-vox-section property xyz">
Voxel volume size <span>m</span> Voxel volume size <span>m</span>

View file

@ -611,6 +611,7 @@ function loaded() {
var elModelAnimationLastFrame = document.getElementById("property-model-animation-last-frame"); var elModelAnimationLastFrame = document.getElementById("property-model-animation-last-frame");
var elModelAnimationLoop = document.getElementById("property-model-animation-loop"); var elModelAnimationLoop = document.getElementById("property-model-animation-loop");
var elModelAnimationHold = document.getElementById("property-model-animation-hold"); var elModelAnimationHold = document.getElementById("property-model-animation-hold");
var elModelAnimationAllowTranslation = document.getElementById("property-model-animation-allow-translation");
var elModelTextures = document.getElementById("property-model-textures"); var elModelTextures = document.getElementById("property-model-textures");
var elModelOriginalTextures = document.getElementById("property-model-original-textures"); var elModelOriginalTextures = document.getElementById("property-model-original-textures");
@ -926,6 +927,7 @@ function loaded() {
elModelAnimationLastFrame.value = properties.animation.lastFrame; elModelAnimationLastFrame.value = properties.animation.lastFrame;
elModelAnimationLoop.checked = properties.animation.loop; elModelAnimationLoop.checked = properties.animation.loop;
elModelAnimationHold.checked = properties.animation.hold; elModelAnimationHold.checked = properties.animation.hold;
elModelAnimationAllowTranslation.checked = properties.animation.allowTranslation;
elModelTextures.value = properties.textures; elModelTextures.value = properties.textures;
setTextareaScrolling(elModelTextures); setTextareaScrolling(elModelTextures);
elModelOriginalTextures.value = properties.originalTextures; elModelOriginalTextures.value = properties.originalTextures;
@ -1276,6 +1278,7 @@ function loaded() {
elModelAnimationLastFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame')); elModelAnimationLastFrame.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('animation', 'lastFrame'));
elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop')); elModelAnimationLoop.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'loop'));
elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold')); elModelAnimationHold.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'hold'));
elModelAnimationAllowTranslation.addEventListener('change', createEmitGroupCheckedPropertyUpdateFunction('animation', 'allowTranslation'));
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures')); elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));

View file

@ -27,7 +27,7 @@
var isPreparing = false; // Explicitly track download request status. var isPreparing = false; // Explicitly track download request status.
var confirmAllPurchases = false; // Set this to "true" to cause Checkout.qml to popup for all items, even if free var confirmAllPurchases = false; // Set this to "true" to cause Checkout.qml to popup for all items, even if free
function injectCommonCode(isDirectoryPage) { function injectCommonCode(isDirectoryPage) {
// Supporting styles from marketplaces.css. // Supporting styles from marketplaces.css.
@ -122,7 +122,7 @@
function injectBuyButtonOnMainPage() { function injectBuyButtonOnMainPage() {
var cost; var cost;
$('.grid-item').find('#price-or-edit').find('a').each(function() { $('.grid-item').find('#price-or-edit').find('a').each(function() {
$(this).attr('data-href', $(this).attr('href')); $(this).attr('data-href', $(this).attr('href'));
$(this).attr('href', '#'); $(this).attr('href', '#');
@ -130,16 +130,16 @@
$(this).closest('.col-xs-3').prev().attr("class", 'col-xs-6'); $(this).closest('.col-xs-3').prev().attr("class", 'col-xs-6');
$(this).closest('.col-xs-3').attr("class", 'col-xs-6'); $(this).closest('.col-xs-3').attr("class", 'col-xs-6');
if (parseInt(cost) > 0) { if (parseInt(cost) > 0) {
var priceElement = $(this).find('.price') var priceElement = $(this).find('.price')
priceElement.css({ "width": "auto", "padding": "3px 5px", "height": "26px" }); priceElement.css({ "width": "auto", "padding": "3px 5px", "height": "26px" });
priceElement.text(parseFloat(cost / 100).toFixed(2) + ' HFC'); priceElement.text(cost + ' HFC');
priceElement.css({ "min-width": priceElement.width() + 10 }); priceElement.css({ "min-width": priceElement.width() + 10 });
} }
}); });
$('.grid-item').find('#price-or-edit').find('a').on('click', function () { $('.grid-item').find('#price-or-edit').find('a').on('click', function () {
buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'), buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'),
$(this).closest('.grid-item').find('.item-title').text(), $(this).closest('.grid-item').find('.item-title').text(),
@ -173,16 +173,17 @@
function injectHiFiItemPageCode() { function injectHiFiItemPageCode() {
if (confirmAllPurchases) { if (confirmAllPurchases) {
var href = $('#side-info').find('.btn').attr('href'); var href = $('#side-info').find('.btn').first().attr('href');
$('#side-info').find('.btn').attr('href', '#'); $('#side-info').find('.btn').first().attr('href', '#');
var cost = $('.item-cost').text(); var cost = $('.item-cost').text();
if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) { if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) {
$('#side-info').find('.btn').html('<span class="glyphicon glyphicon-download" id="buyItemButton"></span>Own Item: ' + (parseFloat(cost / 100).toFixed(2)) + ' HFC'); $('#side-info').find('.btn').first().html('<span class="glyphicon glyphicon-download" id="buyItemButton"></span>Own Item: ' + cost + ' HFC');
} }
$('#side-info').find('.btn').on('click', function () { $('#side-info').find('.btn').first().on('click', function () {
buyButtonClicked(window.location.pathname.split("/")[3], buyButtonClicked(window.location.pathname.split("/")[3],
$('#top-center').find('h1').text(), $('#top-center').find('h1').text(),
$('#creator').find('.value').text(), $('#creator').find('.value').text(),
@ -264,7 +265,7 @@
// Reference: https://clara.io/learn/sdk/api/export // Reference: https://clara.io/learn/sdk/api/export
//var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?zip=true&centerScene=true&alignSceneGround=true&fbxUnit=Meter&fbxVersion=7&fbxEmbedTextures=true&imageFormat=WebGL"; //var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?zip=true&centerScene=true&alignSceneGround=true&fbxUnit=Meter&fbxVersion=7&fbxEmbedTextures=true&imageFormat=WebGL";
// 13 Jan 2017: Specify FBX version 5 and remove some options in order to make Clara.io site more likely to // 13 Jan 2017: Specify FBX version 5 and remove some options in order to make Clara.io site more likely to
// be successful in generating zip files. // be successful in generating zip files.
var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?fbxUnit=Meter&fbxVersion=5&fbxEmbedTextures=true&imageFormat=WebGL"; var XMLHTTPREQUEST_URL = "https://clara.io/api/scenes/{uuid}/export/fbx?fbxUnit=Meter&fbxVersion=5&fbxEmbedTextures=true&imageFormat=WebGL";
@ -447,7 +448,7 @@
cancelClaraDownload(); cancelClaraDownload();
} else { } else {
var parsedJsonMessage = JSON.parse(message); var parsedJsonMessage = JSON.parse(message);
if (parsedJsonMessage.type === "marketplaces") { if (parsedJsonMessage.type === "marketplaces") {
if (parsedJsonMessage.action === "inspectionModeSetting") { if (parsedJsonMessage.action === "inspectionModeSetting") {
confirmAllPurchases = !!parsedJsonMessage.data; confirmAllPurchases = !!parsedJsonMessage.data;

View file

@ -197,6 +197,7 @@
// Description: // Description:
// -Called when a message is received from Checkout.qml. The "message" argument is what is sent from the Checkout QML // -Called when a message is received from Checkout.qml. The "message" argument is what is sent from the Checkout QML
// in the format "{method, params}", like json-rpc. // in the format "{method, params}", like json-rpc.
var isHmdPreviewDisabled = true;
function fromQml(message) { function fromQml(message) {
switch (message.method) { switch (message.method) {
case 'checkout_setUpClicked': case 'checkout_setUpClicked':
@ -231,12 +232,20 @@
case 'purchases_goToMarketplaceClicked': case 'purchases_goToMarketplaceClicked':
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL); tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
break; break;
case 'passphrasePopup_cancelClicked':
case 'needsLogIn_cancelClicked': case 'needsLogIn_cancelClicked':
tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL); tablet.gotoWebScreen(MARKETPLACE_URL_INITIAL, MARKETPLACES_INJECT_SCRIPT_URL);
break; break;
case 'needsLogIn_loginClicked': case 'needsLogIn_loginClicked':
openLoginWindow(); openLoginWindow();
break; break;
case 'disableHmdPreview':
isHmdPreviewDisabled = Menu.isOptionChecked("Disable Preview");
Menu.setIsOptionChecked("Disable Preview", true);
break;
case 'maybeEnableHmdPreview':
Menu.setIsOptionChecked("Disable Preview", isHmdPreviewDisabled);
break;
default: default:
print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message)); print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message));
} }