Merge branch 'master' of git://github.com/highfidelity/hifi into compactvb
|
@ -46,8 +46,14 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||||
|
|
||||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||||
|
|
||||||
const QCommandLineOption clientTypeOption(ASSIGNMENT_TYPE_OVERRIDE_OPTION,
|
QString typeDescription = "run single assignment client of given type\n# | Type\n============================";
|
||||||
"run single assignment client of given type", "type");
|
for (Assignment::Type type = Assignment::FirstType;
|
||||||
|
type != Assignment::AllTypes;
|
||||||
|
type = static_cast<Assignment::Type>(static_cast<int>(type) + 1)) {
|
||||||
|
typeDescription.append(QStringLiteral("\n%1 | %2").arg(QString::number(type), Assignment::typeToString(type)));
|
||||||
|
}
|
||||||
|
const QCommandLineOption clientTypeOption(ASSIGNMENT_TYPE_OVERRIDE_OPTION, typeDescription, "type");
|
||||||
|
|
||||||
parser.addOption(clientTypeOption);
|
parser.addOption(clientTypeOption);
|
||||||
|
|
||||||
const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name");
|
const QCommandLineOption poolOption(ASSIGNMENT_POOL_OPTION, "set assignment pool", "pool-name");
|
||||||
|
|
|
@ -945,7 +945,7 @@ void DomainServer::createStaticAssignmentsForType(Assignment::Type type, const Q
|
||||||
|
|
||||||
void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Assignment::Type>& excludedTypes) {
|
void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Assignment::Type>& excludedTypes) {
|
||||||
// enumerate over all assignment types and see if we've already excluded it
|
// enumerate over all assignment types and see if we've already excluded it
|
||||||
for (Assignment::Type defaultedType = Assignment::AudioMixerType;
|
for (Assignment::Type defaultedType = Assignment::FirstType;
|
||||||
defaultedType != Assignment::AllTypes;
|
defaultedType != Assignment::AllTypes;
|
||||||
defaultedType = static_cast<Assignment::Type>(static_cast<int>(defaultedType) + 1)) {
|
defaultedType = static_cast<Assignment::Type>(static_cast<int>(defaultedType) + 1)) {
|
||||||
if (!excludedTypes.contains(defaultedType) && defaultedType != Assignment::AgentType) {
|
if (!excludedTypes.contains(defaultedType) && defaultedType != Assignment::AgentType) {
|
||||||
|
|
|
@ -12,8 +12,10 @@ function(JOIN VALUES GLUE OUTPUT)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc)
|
if (NOT DEV_BUILD)
|
||||||
generate_qrc(OUTPUT ${INTERFACE_QML_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *.qml *.qss *.js *.html *.ttf *.gif *.svg *.png *.jpg)
|
set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc)
|
||||||
|
generate_qrc(OUTPUT ${INTERFACE_QML_QRC} PATH ${CMAKE_CURRENT_SOURCE_DIR}/resources GLOBS *.qml *.qss *.js *.html *.ttf *.gif *.svg *.png *.jpg)
|
||||||
|
endif()
|
||||||
|
|
||||||
# set a default root dir for each of our optional externals if it was not passed
|
# set a default root dir for each of our optional externals if it was not passed
|
||||||
set(OPTIONAL_EXTERNALS "LeapMotion")
|
set(OPTIONAL_EXTERNALS "LeapMotion")
|
||||||
|
@ -80,7 +82,9 @@ qt5_wrap_ui(QT_UI_HEADERS "${QT_UI_FILES}")
|
||||||
# add them to the interface source files
|
# add them to the interface source files
|
||||||
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
|
set(INTERFACE_SRCS ${INTERFACE_SRCS} "${QT_UI_HEADERS}" "${QT_RESOURCES}")
|
||||||
|
|
||||||
|
if (NOT DEV_BUILD)
|
||||||
list(APPEND INTERFACE_SRCS ${INTERFACE_QML_QRC})
|
list(APPEND INTERFACE_SRCS ${INTERFACE_QML_QRC})
|
||||||
|
endif()
|
||||||
|
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
install(
|
install(
|
||||||
|
|
|
@ -52,7 +52,11 @@ Item {
|
||||||
targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height
|
targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
var newWidth = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
||||||
|
if(!isNaN(newWidth)) {
|
||||||
|
parent.width = root.width = newWidth;
|
||||||
|
}
|
||||||
|
|
||||||
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||||
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);
|
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y);
|
||||||
}
|
}
|
||||||
|
|
18
interface/resources/qml/OverlayWindowTest.qml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 100
|
||||||
|
height: 100
|
||||||
|
color: "white"
|
||||||
|
Rectangle {
|
||||||
|
width: 10
|
||||||
|
height: 10
|
||||||
|
color: "red"
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: OverlayWindowTestString
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,6 @@ Windows.Window {
|
||||||
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
|
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
|
||||||
destroyOnCloseButton: false
|
destroyOnCloseButton: false
|
||||||
property var source;
|
property var source;
|
||||||
property var component;
|
|
||||||
property var dynamicContent;
|
property var dynamicContent;
|
||||||
|
|
||||||
// Keyboard control properties in case needed by QML content.
|
// Keyboard control properties in case needed by QML content.
|
||||||
|
@ -35,28 +34,9 @@ Windows.Window {
|
||||||
dynamicContent.destroy();
|
dynamicContent.destroy();
|
||||||
dynamicContent = null;
|
dynamicContent = null;
|
||||||
}
|
}
|
||||||
component = Qt.createComponent(source);
|
QmlSurface.load(source, contentHolder, function(newObject) {
|
||||||
console.log("Created component " + component + " from source " + source);
|
dynamicContent = newObject;
|
||||||
}
|
});
|
||||||
|
|
||||||
onComponentChanged: {
|
|
||||||
console.log("Component changed to " + component)
|
|
||||||
populate();
|
|
||||||
}
|
|
||||||
|
|
||||||
function populate() {
|
|
||||||
console.log("Populate called: dynamicContent " + dynamicContent + " component " + component);
|
|
||||||
if (!dynamicContent && component) {
|
|
||||||
if (component.status == Component.Error) {
|
|
||||||
console.log("Error loading component:", component.errorString());
|
|
||||||
} else if (component.status == Component.Ready) {
|
|
||||||
console.log("Building dynamic content");
|
|
||||||
dynamicContent = component.createObject(contentHolder);
|
|
||||||
} else {
|
|
||||||
console.log("Component not yet ready, connecting to status change");
|
|
||||||
component.statusChanged.connect(populate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle message traffic from the script that launched us to the loaded QML
|
// Handle message traffic from the script that launched us to the loaded QML
|
||||||
|
|
|
@ -29,12 +29,12 @@ Original.Button {
|
||||||
|
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
style: ButtonStyle {
|
style: ButtonStyle {
|
||||||
|
|
|
@ -31,12 +31,12 @@ Original.CheckBox {
|
||||||
activeFocusOnPress: true
|
activeFocusOnPress: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: doesnt works for QQC1. check with QQC2
|
// TODO: doesnt works for QQC1. check with QQC2
|
||||||
// onHovered: {
|
// onHovered: {
|
||||||
// tabletInterface.playSound(TabletEnums.ButtonHover);
|
// Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
style: CheckBoxStyle {
|
style: CheckBoxStyle {
|
||||||
|
|
|
@ -36,12 +36,12 @@ CheckBox {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,12 @@ Original.Button {
|
||||||
|
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
style: ButtonStyle {
|
style: ButtonStyle {
|
||||||
|
|
|
@ -41,13 +41,13 @@ Item {
|
||||||
|
|
||||||
onContainsMouseChanged: {
|
onContainsMouseChanged: {
|
||||||
if (containsMouse) {
|
if (containsMouse) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
mouse.accepted = true;
|
mouse.accepted = true;
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
|
|
||||||
webEntity.synthesizeKeyPress(glyph);
|
webEntity.synthesizeKeyPress(glyph);
|
||||||
webEntity.synthesizeKeyPress(glyph, mirrorText);
|
webEntity.synthesizeKeyPress(glyph, mirrorText);
|
||||||
|
|
|
@ -30,12 +30,12 @@ Original.RadioButton {
|
||||||
readonly property int checkRadius: 2
|
readonly property int checkRadius: 2
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: doesnt works for QQC1. check with QQC2
|
// TODO: doesnt works for QQC1. check with QQC2
|
||||||
// onHovered: {
|
// onHovered: {
|
||||||
// tabletInterface.playSound(TabletEnums.ButtonHover);
|
// Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
style: RadioButtonStyle {
|
style: RadioButtonStyle {
|
||||||
|
|
|
@ -49,7 +49,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WebEngineView.LoadFailedStatus === loadRequest.status) {
|
if (WebEngineView.LoadFailedStatus === loadRequest.status) {
|
||||||
console.log(" Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
|
console.log("Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WebEngineView.LoadSucceededStatus === loadRequest.status) {
|
if (WebEngineView.LoadSucceededStatus === loadRequest.status) {
|
||||||
|
|
|
@ -25,13 +25,13 @@ Preference {
|
||||||
id: button
|
id: button
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
preference.trigger();
|
preference.trigger();
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
width: 180
|
width: 180
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
|
@ -41,12 +41,12 @@ Preference {
|
||||||
id: checkBox
|
id: checkBox
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
|
|
|
@ -246,12 +246,12 @@ Item {
|
||||||
anchors.fill: parent;
|
anchors.fill: parent;
|
||||||
acceptedButtons: Qt.LeftButton;
|
acceptedButtons: Qt.LeftButton;
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
goFunction("hifi://" + hifiUrl);
|
goFunction("hifi://" + hifiUrl);
|
||||||
}
|
}
|
||||||
hoverEnabled: true;
|
hoverEnabled: true;
|
||||||
onEntered: {
|
onEntered: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
hoverThunk();
|
hoverThunk();
|
||||||
}
|
}
|
||||||
onExited: unhoverThunk();
|
onExited: unhoverThunk();
|
||||||
|
@ -269,7 +269,7 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function go() {
|
function go() {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
goFunction(drillDownToPlace ? ("/places/" + placeName) : ("/user_stories/" + storyId));
|
goFunction(drillDownToPlace ? ("/places/" + placeName) : ("/user_stories/" + storyId));
|
||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|
|
@ -45,11 +45,13 @@ OriginalDesktop.Desktop {
|
||||||
Toolbar {
|
Toolbar {
|
||||||
id: sysToolbar;
|
id: sysToolbar;
|
||||||
objectName: "com.highfidelity.interface.toolbar.system";
|
objectName: "com.highfidelity.interface.toolbar.system";
|
||||||
|
property var tablet: Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined;
|
anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined;
|
||||||
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
|
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
|
||||||
x: sysToolbar.x
|
x: sysToolbar.x
|
||||||
y: 50
|
y: 50
|
||||||
shown: true
|
buttonModel: tablet.buttons;
|
||||||
|
shown: tablet.toolbarMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
|
|
|
@ -61,12 +61,12 @@ Rectangle {
|
||||||
scrollGestureEnabled: false;
|
scrollGestureEnabled: false;
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Audio.muted = !Audio.muted;
|
Audio.muted = !Audio.muted;
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
drag.target: dragTarget;
|
drag.target: dragTarget;
|
||||||
onContainsMouseChanged: {
|
onContainsMouseChanged: {
|
||||||
if (containsMouse) {
|
if (containsMouse) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,11 @@ Rectangle {
|
||||||
property bool debugCheckoutSuccess: false;
|
property bool debugCheckoutSuccess: false;
|
||||||
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
|
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
|
||||||
property bool isWearable;
|
property bool isWearable;
|
||||||
|
property string referrer;
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.white;
|
color: hifi.colors.white;
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onWalletStatusResult: {
|
onWalletStatusResult: {
|
||||||
if (walletStatus === 0) {
|
if (walletStatus === 0) {
|
||||||
|
@ -59,6 +60,7 @@ Rectangle {
|
||||||
} else if (walletStatus === 2) {
|
} else if (walletStatus === 2) {
|
||||||
if (root.activeView !== "passphraseModal") {
|
if (root.activeView !== "passphraseModal") {
|
||||||
root.activeView = "passphraseModal";
|
root.activeView = "passphraseModal";
|
||||||
|
UserActivityLogger.commercePassphraseEntry("marketplace checkout");
|
||||||
}
|
}
|
||||||
} else if (walletStatus === 3) {
|
} else if (walletStatus === 3) {
|
||||||
authSuccessStep();
|
authSuccessStep();
|
||||||
|
@ -71,7 +73,7 @@ Rectangle {
|
||||||
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else {
|
} else {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +116,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemIdChanged: {
|
onItemIdChanged: {
|
||||||
commerce.inventory();
|
Commerce.inventory();
|
||||||
itemPreviewImage.source = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/" + itemId + "/thumbnail/hifi-mp-" + itemId + ".jpg";
|
itemPreviewImage.source = "https://hifi-metaverse.s3-us-west-1.amazonaws.com/marketplace/previews/" + itemId + "/thumbnail/hifi-mp-" + itemId + ".jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,14 +125,14 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
onItemPriceChanged: {
|
onItemPriceChanged: {
|
||||||
commerce.balance();
|
Commerce.balance();
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: notSetUpTimer;
|
id: notSetUpTimer;
|
||||||
interval: 200;
|
interval: 200;
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId});
|
sendToScript({method: 'checkout_walletNotSetUp', itemId: itemId, referrer: referrer});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +204,7 @@ Rectangle {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
purchasesReceived = false;
|
purchasesReceived = false;
|
||||||
balanceReceived = false;
|
balanceReceived = false;
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +225,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
commerce.getLoginStatus();
|
Commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,9 +475,9 @@ Rectangle {
|
||||||
if (itemIsJson) {
|
if (itemIsJson) {
|
||||||
buyButton.enabled = false;
|
buyButton.enabled = false;
|
||||||
if (!root.shouldBuyWithControlledFailure) {
|
if (!root.shouldBuyWithControlledFailure) {
|
||||||
commerce.buy(itemId, itemPrice);
|
Commerce.buy(itemId, itemPrice);
|
||||||
} else {
|
} else {
|
||||||
commerce.buy(itemId, itemPrice, true);
|
Commerce.buy(itemId, itemPrice, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (urlHandler.canHandleUrl(itemHref)) {
|
if (urlHandler.canHandleUrl(itemHref)) {
|
||||||
|
@ -876,6 +878,7 @@ Rectangle {
|
||||||
itemName = message.params.itemName;
|
itemName = message.params.itemName;
|
||||||
root.itemPrice = message.params.itemPrice;
|
root.itemPrice = message.params.itemPrice;
|
||||||
itemHref = message.params.itemHref;
|
itemHref = message.params.itemHref;
|
||||||
|
referrer = message.params.referrer;
|
||||||
setBuyText();
|
setBuyText();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -939,8 +942,8 @@ Rectangle {
|
||||||
}
|
}
|
||||||
root.balanceReceived = false;
|
root.balanceReceived = false;
|
||||||
root.purchasesReceived = false;
|
root.purchasesReceived = false;
|
||||||
commerce.inventory();
|
Commerce.inventory();
|
||||||
commerce.balance();
|
Commerce.balance();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -31,14 +31,14 @@ Item {
|
||||||
|
|
||||||
height: mainContainer.height + additionalDropdownHeight;
|
height: mainContainer.height + additionalDropdownHeight;
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onWalletStatusResult: {
|
onWalletStatusResult: {
|
||||||
if (walletStatus === 0) {
|
if (walletStatus === 0) {
|
||||||
sendToParent({method: "needsLogIn"});
|
sendToParent({method: "needsLogIn"});
|
||||||
} else if (walletStatus === 3) {
|
} else if (walletStatus === 3) {
|
||||||
commerce.getSecurityImage();
|
Commerce.getSecurityImage();
|
||||||
} else if (walletStatus > 3) {
|
} else if (walletStatus > 3) {
|
||||||
console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus);
|
console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ Item {
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
sendToParent({method: "needsLogIn"});
|
sendToParent({method: "needsLogIn"});
|
||||||
} else {
|
} else {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,13 +61,13 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
commerce.getLoginStatus();
|
Commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ Rectangle {
|
||||||
property bool isCertificateInvalid: false;
|
property bool isCertificateInvalid: false;
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.faintGray;
|
color: hifi.colors.faintGray;
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onCertificateInfoResult: {
|
onCertificateInfoResult: {
|
||||||
if (result.status !== 'success') {
|
if (result.status !== 'success') {
|
||||||
|
@ -109,7 +109,7 @@ Rectangle {
|
||||||
|
|
||||||
onCertificateIdChanged: {
|
onCertificateIdChanged: {
|
||||||
if (certificateId !== "") {
|
if (certificateId !== "") {
|
||||||
commerce.certificateInfo(certificateId);
|
Commerce.certificateInfo(certificateId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,8 @@ Rectangle {
|
||||||
property bool isDebuggingFirstUseTutorial: false;
|
property bool isDebuggingFirstUseTutorial: false;
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.white;
|
color: hifi.colors.white;
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onWalletStatusResult: {
|
onWalletStatusResult: {
|
||||||
if (walletStatus === 0) {
|
if (walletStatus === 0) {
|
||||||
|
@ -54,13 +54,14 @@ Rectangle {
|
||||||
} else if (walletStatus === 2) {
|
} else if (walletStatus === 2) {
|
||||||
if (root.activeView !== "passphraseModal") {
|
if (root.activeView !== "passphraseModal") {
|
||||||
root.activeView = "passphraseModal";
|
root.activeView = "passphraseModal";
|
||||||
|
UserActivityLogger.commercePassphraseEntry("marketplace purchases");
|
||||||
}
|
}
|
||||||
} else if (walletStatus === 3) {
|
} else if (walletStatus === 3) {
|
||||||
if ((Settings.getValue("isFirstUseOfPurchases", true) || root.isDebuggingFirstUseTutorial) && root.activeView !== "firstUseTutorial") {
|
if ((Settings.getValue("isFirstUseOfPurchases", true) || root.isDebuggingFirstUseTutorial) && root.activeView !== "firstUseTutorial") {
|
||||||
root.activeView = "firstUseTutorial";
|
root.activeView = "firstUseTutorial";
|
||||||
} else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") {
|
} else if (!Settings.getValue("isFirstUseOfPurchases", true) && root.activeView === "initialize") {
|
||||||
root.activeView = "purchasesMain";
|
root.activeView = "purchasesMain";
|
||||||
commerce.inventory();
|
Commerce.inventory();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("ERROR in Purchases.qml: Unknown wallet status: " + walletStatus);
|
console.log("ERROR in Purchases.qml: Unknown wallet status: " + walletStatus);
|
||||||
|
@ -71,7 +72,7 @@ Rectangle {
|
||||||
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else {
|
} else {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +198,7 @@ Rectangle {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
securityImageResultReceived = false;
|
securityImageResultReceived = false;
|
||||||
purchasesReceived = false;
|
purchasesReceived = false;
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +219,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
commerce.getLoginStatus();
|
Commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +234,7 @@ Rectangle {
|
||||||
onSendSignalToParent: {
|
onSendSignalToParent: {
|
||||||
if (msg.method === "authSuccess") {
|
if (msg.method === "authSuccess") {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
} else {
|
} else {
|
||||||
sendToScript(msg);
|
sendToScript(msg);
|
||||||
}
|
}
|
||||||
|
@ -254,7 +255,7 @@ Rectangle {
|
||||||
case 'tutorial_finished':
|
case 'tutorial_finished':
|
||||||
Settings.setValue("isFirstUseOfPurchases", false);
|
Settings.setValue("isFirstUseOfPurchases", false);
|
||||||
root.activeView = "purchasesMain";
|
root.activeView = "purchasesMain";
|
||||||
commerce.inventory();
|
Commerce.inventory();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -594,7 +595,7 @@ Rectangle {
|
||||||
if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) {
|
if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) {
|
||||||
console.log("Refreshing Purchases...");
|
console.log("Refreshing Purchases...");
|
||||||
root.pendingInventoryReply = true;
|
root.pendingInventoryReply = true;
|
||||||
commerce.inventory();
|
Commerce.inventory();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ Item {
|
||||||
property string keyFilePath;
|
property string keyFilePath;
|
||||||
property bool showDebugButtons: true;
|
property bool showDebugButtons: true;
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onKeyFilePathIfExistsResult: {
|
onKeyFilePathIfExistsResult: {
|
||||||
root.keyFilePath = path;
|
root.keyFilePath = path;
|
||||||
|
@ -37,7 +37,7 @@ Item {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getKeyFilePathIfExists();
|
Commerce.getKeyFilePathIfExists();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,37 @@ Item {
|
||||||
// Style
|
// Style
|
||||||
color: hifi.colors.blueHighlight;
|
color: hifi.colors.blueHighlight;
|
||||||
}
|
}
|
||||||
|
HifiControlsUit.Button {
|
||||||
|
id: clearCachedPassphraseButton;
|
||||||
|
visible: root.showDebugButtons;
|
||||||
|
color: hifi.buttons.black;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.left: helpTitleText.right;
|
||||||
|
anchors.leftMargin: 20;
|
||||||
|
height: 40;
|
||||||
|
width: 150;
|
||||||
|
text: "DBG: Clear Pass";
|
||||||
|
onClicked: {
|
||||||
|
Commerce.setPassphrase("");
|
||||||
|
sendSignalToWallet({method: 'passphraseReset'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HifiControlsUit.Button {
|
||||||
|
id: resetButton;
|
||||||
|
visible: root.showDebugButtons;
|
||||||
|
color: hifi.buttons.red;
|
||||||
|
colorScheme: hifi.colorSchemes.dark;
|
||||||
|
anchors.top: clearCachedPassphraseButton.top;
|
||||||
|
anchors.left: clearCachedPassphraseButton.right;
|
||||||
|
height: 40;
|
||||||
|
width: 150;
|
||||||
|
text: "DBG: RST Wallet";
|
||||||
|
onClicked: {
|
||||||
|
Commerce.reset();
|
||||||
|
sendSignalToWallet({method: 'walletReset'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: helpModel;
|
id: helpModel;
|
||||||
|
|
|
@ -30,8 +30,8 @@ Item {
|
||||||
source: "images/wallet-bg.jpg";
|
source: "images/wallet-bg.jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -25,10 +25,6 @@ Item {
|
||||||
|
|
||||||
id: root;
|
id: root;
|
||||||
|
|
||||||
SecurityImageModel {
|
|
||||||
id: securityImageModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Username Text
|
// Username Text
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: usernameText;
|
id: usernameText;
|
||||||
|
|
|
@ -36,8 +36,8 @@ Item {
|
||||||
source: "images/wallet-bg.jpg";
|
source: "images/wallet-bg.jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onSecurityImageResult: {
|
onSecurityImageResult: {
|
||||||
titleBarSecurityImage.source = "";
|
titleBarSecurityImage.source = "";
|
||||||
|
@ -50,8 +50,12 @@ Item {
|
||||||
submitPassphraseInputButton.enabled = true;
|
submitPassphraseInputButton.enabled = true;
|
||||||
if (!isAuthenticated) {
|
if (!isAuthenticated) {
|
||||||
errorText.text = "Authentication failed - please try again.";
|
errorText.text = "Authentication failed - please try again.";
|
||||||
|
passphraseField.error = true;
|
||||||
|
UserActivityLogger.commercePassphraseAuthenticationStatus("auth failure");
|
||||||
} else {
|
} else {
|
||||||
sendSignalToParent({method: 'authSuccess'});;
|
sendSignalToParent({method: 'authSuccess'});
|
||||||
|
passphraseField.error = false;
|
||||||
|
UserActivityLogger.commercePassphraseAuthenticationStatus("auth success");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,6 +74,7 @@ Item {
|
||||||
// TODO: Fix this unlikely bug
|
// TODO: Fix this unlikely bug
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
passphraseField.error = false;
|
||||||
passphraseField.focus = true;
|
passphraseField.focus = true;
|
||||||
sendSignalToParent({method: 'disableHmdPreview'});
|
sendSignalToParent({method: 'disableHmdPreview'});
|
||||||
} else {
|
} else {
|
||||||
|
@ -208,7 +213,7 @@ Item {
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
submitPassphraseInputButton.enabled = false;
|
submitPassphraseInputButton.enabled = false;
|
||||||
commerce.setPassphrase(passphraseField.text);
|
Commerce.setPassphrase(passphraseField.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +253,7 @@ Item {
|
||||||
source: "image://security/securityImage";
|
source: "image://security/securityImage";
|
||||||
cache: false;
|
cache: false;
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
commerce.getSecurityImage();
|
Commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
|
@ -316,7 +321,7 @@ Item {
|
||||||
text: "Submit"
|
text: "Submit"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
submitPassphraseInputButton.enabled = false;
|
submitPassphraseInputButton.enabled = false;
|
||||||
commerce.setPassphrase(passphraseField.text);
|
Commerce.setPassphrase(passphraseField.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +341,7 @@ Item {
|
||||||
text: "Cancel"
|
text: "Cancel"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
sendSignalToParent({method: 'passphrasePopup_cancelClicked'});
|
sendSignalToParent({method: 'passphrasePopup_cancelClicked'});
|
||||||
|
UserActivityLogger.commercePassphraseAuthenticationStatus("passphrase modal cancelled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ Item {
|
||||||
propagateComposedEvents: false;
|
propagateComposedEvents: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
onSecurityImageResult: {
|
onSecurityImageResult: {
|
||||||
passphrasePageSecurityImage.source = "";
|
passphrasePageSecurityImage.source = "";
|
||||||
passphrasePageSecurityImage.source = "image://security/securityImage";
|
passphrasePageSecurityImage.source = "image://security/securityImage";
|
||||||
|
@ -54,6 +54,9 @@ Item {
|
||||||
// TODO: Fix this unlikely bug
|
// TODO: Fix this unlikely bug
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
passphraseField.error = false;
|
||||||
|
passphraseFieldAgain.error = false;
|
||||||
|
currentPassphraseField.error = false;
|
||||||
if (root.shouldImmediatelyFocus) {
|
if (root.shouldImmediatelyFocus) {
|
||||||
focusFirstTextField();
|
focusFirstTextField();
|
||||||
}
|
}
|
||||||
|
@ -160,7 +163,7 @@ Item {
|
||||||
source: "image://security/securityImage";
|
source: "image://security/securityImage";
|
||||||
cache: false;
|
cache: false;
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
commerce.getSecurityImage();
|
Commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
|
@ -283,7 +286,7 @@ Item {
|
||||||
passphraseFieldAgain.error = false;
|
passphraseFieldAgain.error = false;
|
||||||
currentPassphraseField.error = false;
|
currentPassphraseField.error = false;
|
||||||
setErrorText("");
|
setErrorText("");
|
||||||
commerce.changePassphrase(currentPassphraseField.text, passphraseField.text);
|
Commerce.changePassphrase(currentPassphraseField.text, passphraseField.text);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ Item {
|
||||||
id: root;
|
id: root;
|
||||||
property string keyFilePath;
|
property string keyFilePath;
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onKeyFilePathIfExistsResult: {
|
onKeyFilePathIfExistsResult: {
|
||||||
root.keyFilePath = path;
|
root.keyFilePath = path;
|
||||||
|
@ -234,7 +234,7 @@ Item {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getKeyFilePathIfExists();
|
Commerce.getKeyFilePathIfExists();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,8 @@ Item {
|
||||||
id: root;
|
id: root;
|
||||||
property bool justSubmitted: false;
|
property bool justSubmitted: false;
|
||||||
|
|
||||||
SecurityImageModel {
|
Connections {
|
||||||
id: securityImageModel;
|
target: Commerce;
|
||||||
}
|
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
|
||||||
id: commerce;
|
|
||||||
|
|
||||||
onSecurityImageResult: {
|
onSecurityImageResult: {
|
||||||
securityImageChangePageSecurityImage.source = "";
|
securityImageChangePageSecurityImage.source = "";
|
||||||
|
@ -213,4 +209,8 @@ Item {
|
||||||
securityImageSubmitButton.enabled = true;
|
securityImageSubmitButton.enabled = true;
|
||||||
securityImageSubmitButton.text = "Submit";
|
securityImageSubmitButton.text = "Submit";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initModel() {
|
||||||
|
securityImageSelection.initModel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,29 +15,28 @@ import QtQuick 2.5
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
id: root;
|
id: root;
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/01.jpg"
|
function initModel() {
|
||||||
securityImageEnumValue: 1;
|
var array = [];
|
||||||
|
while (array.length < 6) {
|
||||||
|
// We currently have 34 security images to choose from
|
||||||
|
var randomNumber = Math.floor(Math.random() * 34) + 1;
|
||||||
|
if (array.indexOf(randomNumber) > -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
array[array.length] = randomNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
var modelElement;
|
||||||
|
|
||||||
|
for (var i = 0; i < 6; i++) {
|
||||||
|
modelElement = { "sourcePath":"images/" + addLeadingZero(array[i]) + ".jpg", "securityImageEnumValue": (i + 1) }
|
||||||
|
root.insert(i, modelElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/02.jpg"
|
function addLeadingZero(n) {
|
||||||
securityImageEnumValue: 2;
|
return n < 10 ? '0' + n : '' + n;
|
||||||
}
|
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/03.jpg"
|
|
||||||
securityImageEnumValue: 3;
|
|
||||||
}
|
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/04.jpg"
|
|
||||||
securityImageEnumValue: 4;
|
|
||||||
}
|
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/05.jpg"
|
|
||||||
securityImageEnumValue: 5;
|
|
||||||
}
|
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/06.jpg"
|
|
||||||
securityImageEnumValue: 6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getImagePathFromImageID(imageID) {
|
function getImagePathFromImageID(imageID) {
|
||||||
|
|
|
@ -95,6 +95,10 @@ Item {
|
||||||
function getSelectedImageIndex() {
|
function getSelectedImageIndex() {
|
||||||
return gridModel.get(securityImageGrid.currentIndex).securityImageEnumValue;
|
return gridModel.get(securityImageGrid.currentIndex).securityImageEnumValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initModel() {
|
||||||
|
gridModel.initModel();
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// FUNCTION DEFINITIONS END
|
// FUNCTION DEFINITIONS END
|
||||||
//
|
//
|
||||||
|
|
|
@ -25,8 +25,8 @@ Item {
|
||||||
|
|
||||||
id: root;
|
id: root;
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Unavailable"
|
// "Unavailable"
|
||||||
|
|
|
@ -31,13 +31,15 @@ Rectangle {
|
||||||
property bool keyboardRaised: false;
|
property bool keyboardRaised: false;
|
||||||
property bool isPassword: false;
|
property bool isPassword: false;
|
||||||
|
|
||||||
|
anchors.fill: (typeof parent === undefined) ? undefined : parent;
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
anchors.fill: parent;
|
anchors.fill: parent;
|
||||||
source: "images/wallet-bg.jpg";
|
source: "images/wallet-bg.jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onWalletStatusResult: {
|
onWalletStatusResult: {
|
||||||
if (walletStatus === 0) {
|
if (walletStatus === 0) {
|
||||||
|
@ -47,7 +49,7 @@ Rectangle {
|
||||||
} else if (walletStatus === 1) {
|
} else if (walletStatus === 1) {
|
||||||
if (root.activeView !== "walletSetup") {
|
if (root.activeView !== "walletSetup") {
|
||||||
root.activeView = "walletSetup";
|
root.activeView = "walletSetup";
|
||||||
commerce.resetLocalWalletOnly();
|
Commerce.resetLocalWalletOnly();
|
||||||
var timestamp = new Date();
|
var timestamp = new Date();
|
||||||
walletSetup.startingTimestamp = timestamp;
|
walletSetup.startingTimestamp = timestamp;
|
||||||
walletSetup.setupAttemptID = generateUUID();
|
walletSetup.setupAttemptID = generateUUID();
|
||||||
|
@ -57,10 +59,13 @@ Rectangle {
|
||||||
} else if (walletStatus === 2) {
|
} else if (walletStatus === 2) {
|
||||||
if (root.activeView !== "passphraseModal") {
|
if (root.activeView !== "passphraseModal") {
|
||||||
root.activeView = "passphraseModal";
|
root.activeView = "passphraseModal";
|
||||||
|
UserActivityLogger.commercePassphraseEntry("wallet app");
|
||||||
}
|
}
|
||||||
} else if (walletStatus === 3) {
|
} else if (walletStatus === 3) {
|
||||||
root.activeView = "walletHome";
|
if (root.activeView !== "walletSetup") {
|
||||||
commerce.getSecurityImage();
|
root.activeView = "walletHome";
|
||||||
|
Commerce.getSecurityImage();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus);
|
console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +75,7 @@ Rectangle {
|
||||||
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else if (isLoggedIn) {
|
} else if (isLoggedIn) {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,10 +87,6 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityImageModel {
|
|
||||||
id: securityImageModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiCommerceCommon.CommerceLightbox {
|
HifiCommerceCommon.CommerceLightbox {
|
||||||
id: lightboxPopup;
|
id: lightboxPopup;
|
||||||
visible: false;
|
visible: false;
|
||||||
|
@ -180,7 +181,7 @@ Rectangle {
|
||||||
if (msg.method === 'walletSetup_finished') {
|
if (msg.method === 'walletSetup_finished') {
|
||||||
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
|
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
|
||||||
root.activeView = "initialize";
|
root.activeView = "initialize";
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
} else if (msg.referrer === 'purchases') {
|
} else if (msg.referrer === 'purchases') {
|
||||||
sendToScript({method: 'goToPurchases'});
|
sendToScript({method: 'goToPurchases'});
|
||||||
} else {
|
} else {
|
||||||
|
@ -209,17 +210,19 @@ Rectangle {
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onSendSignalToWallet: {
|
onSendSignalToWallet: {
|
||||||
if (msg.method === 'walletSetup_raiseKeyboard') {
|
if (passphraseChange.visible) {
|
||||||
root.keyboardRaised = true;
|
if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||||
root.isPassword = msg.isPasswordField;
|
root.keyboardRaised = true;
|
||||||
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
root.isPassword = msg.isPasswordField;
|
||||||
root.keyboardRaised = false;
|
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
||||||
} else if (msg.method === 'walletSecurity_changePassphraseCancelled') {
|
root.keyboardRaised = false;
|
||||||
root.activeView = "security";
|
} else if (msg.method === 'walletSecurity_changePassphraseCancelled') {
|
||||||
} else if (msg.method === 'walletSecurity_changePassphraseSuccess') {
|
root.activeView = "security";
|
||||||
root.activeView = "security";
|
} else if (msg.method === 'walletSecurity_changePassphraseSuccess') {
|
||||||
} else {
|
root.activeView = "security";
|
||||||
sendToScript(msg);
|
} else {
|
||||||
|
sendToScript(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,7 +263,7 @@ Rectangle {
|
||||||
color: hifi.colors.baseGray;
|
color: hifi.colors.baseGray;
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +284,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
commerce.getLoginStatus();
|
Commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +298,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
onSendSignalToParent: {
|
onSendSignalToParent: {
|
||||||
if (msg.method === "authSuccess") {
|
if (msg.method === "authSuccess") {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
} else {
|
} else {
|
||||||
sendToScript(msg);
|
sendToScript(msg);
|
||||||
}
|
}
|
||||||
|
@ -342,6 +345,7 @@ Rectangle {
|
||||||
passphraseChange.clearPassphraseFields();
|
passphraseChange.clearPassphraseFields();
|
||||||
passphraseChange.resetSubmitButton();
|
passphraseChange.resetSubmitButton();
|
||||||
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||||
|
securityImageChange.initModel();
|
||||||
root.activeView = "securityImageChange";
|
root.activeView = "securityImageChange";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ Item {
|
||||||
property bool historyReceived: false;
|
property bool historyReceived: false;
|
||||||
property int pendingCount: 0;
|
property int pendingCount: 0;
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onBalanceResult : {
|
onBalanceResult : {
|
||||||
balanceText.text = result.data.balance;
|
balanceText.text = result.data.balance;
|
||||||
|
@ -135,8 +135,8 @@ Item {
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
historyReceived = false;
|
historyReceived = false;
|
||||||
commerce.balance();
|
Commerce.balance();
|
||||||
commerce.history();
|
Commerce.history();
|
||||||
} else {
|
} else {
|
||||||
refreshTimer.stop();
|
refreshTimer.stop();
|
||||||
}
|
}
|
||||||
|
@ -165,8 +165,8 @@ Item {
|
||||||
interval: 4000;
|
interval: 4000;
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
console.log("Refreshing Wallet Home...");
|
console.log("Refreshing Wallet Home...");
|
||||||
commerce.balance();
|
Commerce.balance();
|
||||||
commerce.history();
|
Commerce.history();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ Item {
|
||||||
source: "images/wallet-bg.jpg";
|
source: "images/wallet-bg.jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
|
|
||||||
onSecurityImageResult: {
|
onSecurityImageResult: {
|
||||||
if (!exists && root.lastPage === "step_2") {
|
if (!exists && root.lastPage === "step_2") {
|
||||||
|
@ -236,6 +236,7 @@ Item {
|
||||||
height: 50;
|
height: 50;
|
||||||
text: "Set Up Wallet";
|
text: "Set Up Wallet";
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
securityImageSelection.initModel();
|
||||||
root.activeView = "step_2";
|
root.activeView = "step_2";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +252,7 @@ Item {
|
||||||
height: 50;
|
height: 50;
|
||||||
text: "Cancel";
|
text: "Cancel";
|
||||||
onClicked: {
|
onClicked: {
|
||||||
sendSignalToWallet({method: 'walletSetup_cancelClicked'});
|
sendSignalToWallet({method: 'walletSetup_cancelClicked', referrer: root.referrer });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,7 +366,7 @@ Item {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.lastPage = "step_2";
|
root.lastPage = "step_2";
|
||||||
var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex())
|
var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex())
|
||||||
commerce.chooseSecurityImage(securityImagePath);
|
Commerce.chooseSecurityImage(securityImagePath);
|
||||||
root.activeView = "step_3";
|
root.activeView = "step_3";
|
||||||
passphraseSelection.clearPassphraseFields();
|
passphraseSelection.clearPassphraseFields();
|
||||||
}
|
}
|
||||||
|
@ -448,7 +449,7 @@ Item {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getWalletAuthenticatedStatus();
|
Commerce.getWalletAuthenticatedStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,7 +535,7 @@ Item {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (passphraseSelection.validateAndSubmitPassphrase()) {
|
if (passphraseSelection.validateAndSubmitPassphrase()) {
|
||||||
root.lastPage = "step_3";
|
root.lastPage = "step_3";
|
||||||
commerce.generateKeyPair();
|
Commerce.generateKeyPair();
|
||||||
root.activeView = "step_4";
|
root.activeView = "step_4";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -667,7 +668,7 @@ Item {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getKeyFilePathIfExists();
|
Commerce.getKeyFilePathIfExists();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 35 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/07.jpg
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/08.jpg
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/09.jpg
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/10.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/11.jpg
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/12.jpg
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/13.jpg
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/14.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/15.jpg
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/16.jpg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/17.jpg
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/18.jpg
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/19.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/20.jpg
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/21.jpg
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/22.jpg
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/23.jpg
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/24.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/25.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/26.jpg
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/27.jpg
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/28.jpg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/29.jpg
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/30.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/31.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/32.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/33.jpg
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
interface/resources/qml/hifi/commerce/wallet/images/34.jpg
Normal file
After Width: | Height: | Size: 50 KiB |
|
@ -123,11 +123,11 @@ Item {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
enabled: true
|
enabled: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
newEntityButton.clicked();
|
newEntityButton.clicked();
|
||||||
}
|
}
|
||||||
onEntered: {
|
onEntered: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
newEntityButton.state = "hover state";
|
newEntityButton.state = "hover state";
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
|
|
|
@ -1,261 +0,0 @@
|
||||||
import QtQuick 2.5
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
|
|
||||||
import "../../styles-uit"
|
|
||||||
import "../audio" as HifiAudio
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: tablet
|
|
||||||
objectName: "tablet"
|
|
||||||
property int rowIndex: 6 // by default
|
|
||||||
property int columnIndex: 1 // point to 'go to location'
|
|
||||||
property int count: (flowMain.children.length - 1)
|
|
||||||
|
|
||||||
// used to look up a button by its uuid
|
|
||||||
function findButtonIndex(uuid) {
|
|
||||||
if (!uuid) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i in flowMain.children) {
|
|
||||||
var child = flowMain.children[i];
|
|
||||||
if (child.uuid === uuid) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortButtons() {
|
|
||||||
var children = [];
|
|
||||||
for (var i = 0; i < flowMain.children.length; i++) {
|
|
||||||
children[i] = flowMain.children[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
children.sort(function (a, b) {
|
|
||||||
if (a.sortOrder === b.sortOrder) {
|
|
||||||
// subsort by stableOrder, because JS sort is not stable in qml.
|
|
||||||
return a.stableOrder - b.stableOrder;
|
|
||||||
} else {
|
|
||||||
return a.sortOrder - b.sortOrder;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
flowMain.children = children;
|
|
||||||
}
|
|
||||||
|
|
||||||
// called by C++ code when a button should be added to the tablet
|
|
||||||
function addButtonProxy(properties) {
|
|
||||||
var component = Qt.createComponent("TabletButton.qml");
|
|
||||||
var button = component.createObject(flowMain);
|
|
||||||
|
|
||||||
// copy all properites to button
|
|
||||||
var keys = Object.keys(properties).forEach(function (key) {
|
|
||||||
button[key] = properties[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
// pass a reference to the tabletRoot object to the button.
|
|
||||||
if (tabletRoot) {
|
|
||||||
button.tabletRoot = tabletRoot;
|
|
||||||
} else {
|
|
||||||
button.tabletRoot = parent.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
sortButtons();
|
|
||||||
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
// called by C++ code when a button should be removed from the tablet
|
|
||||||
function removeButtonProxy(properties) {
|
|
||||||
var index = findButtonIndex(properties.uuid);
|
|
||||||
if (index < 0) {
|
|
||||||
console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid);
|
|
||||||
} else {
|
|
||||||
flowMain.children[index].destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: bgTopBar
|
|
||||||
height: 90
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: 0
|
|
||||||
left: parent.left
|
|
||||||
leftMargin: 0
|
|
||||||
right: parent.right
|
|
||||||
rightMargin: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
gradient: Gradient {
|
|
||||||
GradientStop {
|
|
||||||
position: 0
|
|
||||||
color: "#2b2b2b"
|
|
||||||
}
|
|
||||||
|
|
||||||
GradientStop {
|
|
||||||
position: 1
|
|
||||||
color: "#1e1e1e"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiAudio.MicBar {
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
leftMargin: 30
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: 150
|
|
||||||
height: 50
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 30
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: bgMain
|
|
||||||
gradient: Gradient {
|
|
||||||
GradientStop {
|
|
||||||
position: 0
|
|
||||||
color: "#2b2b2b"
|
|
||||||
}
|
|
||||||
|
|
||||||
GradientStop {
|
|
||||||
position: 1
|
|
||||||
color: "#0f212e"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.bottomMargin: 0
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 0
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: 0
|
|
||||||
anchors.top: bgTopBar.bottom
|
|
||||||
anchors.topMargin: 0
|
|
||||||
|
|
||||||
Flickable {
|
|
||||||
id: flickable
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
contentWidth: parent.width
|
|
||||||
contentHeight: flowMain.childrenRect.height + flowMain.anchors.topMargin + flowMain.anchors.bottomMargin + flowMain.spacing
|
|
||||||
clip: true
|
|
||||||
Flow {
|
|
||||||
id: flowMain
|
|
||||||
spacing: 16
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 30
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: 30
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.bottomMargin: 30
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 30
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCurrentItemState(state) {
|
|
||||||
var index = rowIndex + columnIndex;
|
|
||||||
|
|
||||||
if (index >= 0 && index <= count ) {
|
|
||||||
flowMain.children[index].state = state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextItem() {
|
|
||||||
setCurrentItemState("base state");
|
|
||||||
var nextColumnIndex = (columnIndex + 3 + 1) % 3;
|
|
||||||
var nextIndex = rowIndex + nextColumnIndex;
|
|
||||||
if(nextIndex <= count) {
|
|
||||||
columnIndex = nextColumnIndex;
|
|
||||||
};
|
|
||||||
setCurrentItemState("hover state");
|
|
||||||
}
|
|
||||||
|
|
||||||
function previousItem() {
|
|
||||||
setCurrentItemState("base state");
|
|
||||||
var prevIndex = (columnIndex + 3 - 1) % 3;
|
|
||||||
if((rowIndex + prevIndex) <= count){
|
|
||||||
columnIndex = prevIndex;
|
|
||||||
}
|
|
||||||
setCurrentItemState("hover state");
|
|
||||||
}
|
|
||||||
|
|
||||||
function upItem() {
|
|
||||||
setCurrentItemState("base state");
|
|
||||||
rowIndex = rowIndex - 3;
|
|
||||||
if (rowIndex < 0 ) {
|
|
||||||
rowIndex = (count - (count % 3));
|
|
||||||
var index = rowIndex + columnIndex;
|
|
||||||
if(index > count) {
|
|
||||||
rowIndex = rowIndex - 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setCurrentItemState("hover state");
|
|
||||||
}
|
|
||||||
|
|
||||||
function downItem() {
|
|
||||||
setCurrentItemState("base state");
|
|
||||||
rowIndex = rowIndex + 3;
|
|
||||||
var index = rowIndex + columnIndex;
|
|
||||||
if (index > count ) {
|
|
||||||
rowIndex = 0;
|
|
||||||
}
|
|
||||||
setCurrentItemState("hover state");
|
|
||||||
}
|
|
||||||
|
|
||||||
function selectItem() {
|
|
||||||
flowMain.children[rowIndex + columnIndex].clicked();
|
|
||||||
if (tabletRoot) {
|
|
||||||
tabletRoot.playButtonClickSound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onRightPressed: nextItem();
|
|
||||||
Keys.onLeftPressed: previousItem();
|
|
||||||
Keys.onDownPressed: downItem();
|
|
||||||
Keys.onUpPressed: upItem();
|
|
||||||
Keys.onReturnPressed: selectItem();
|
|
||||||
}
|
|
|
@ -123,7 +123,6 @@ Item {
|
||||||
enabled: true
|
enabled: true
|
||||||
preventStealing: true
|
preventStealing: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
console.log("Tablet Button Clicked!");
|
|
||||||
if (tabletButton.inDebugMode) {
|
if (tabletButton.inDebugMode) {
|
||||||
if (tabletButton.isActive) {
|
if (tabletButton.isActive) {
|
||||||
tabletButton.isActive = false;
|
tabletButton.isActive = false;
|
||||||
|
@ -133,12 +132,12 @@ Item {
|
||||||
}
|
}
|
||||||
tabletButton.clicked();
|
tabletButton.clicked();
|
||||||
if (tabletRoot) {
|
if (tabletRoot) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEntered: {
|
onEntered: {
|
||||||
tabletButton.isEntered = true;
|
tabletButton.isEntered = true;
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
|
|
||||||
if (tabletButton.isActive) {
|
if (tabletButton.isActive) {
|
||||||
tabletButton.state = "hover active state";
|
tabletButton.state = "hover active state";
|
||||||
|
|
159
interface/resources/qml/hifi/tablet/TabletHome.qml
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
import "."
|
||||||
|
import "../../styles-uit"
|
||||||
|
import "../audio" as HifiAudio
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: tablet
|
||||||
|
objectName: "tablet"
|
||||||
|
property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: bgTopBar
|
||||||
|
height: 90
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
|
||||||
|
gradient: Gradient {
|
||||||
|
GradientStop {
|
||||||
|
position: 0
|
||||||
|
color: "#2b2b2b"
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
position: 1
|
||||||
|
color: "#1e1e1e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiAudio.MicBar {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
leftMargin: 30
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: 150
|
||||||
|
height: 50
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 30
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: bgMain
|
||||||
|
clip: true
|
||||||
|
gradient: Gradient {
|
||||||
|
GradientStop {
|
||||||
|
position: 0
|
||||||
|
color: "#2b2b2b"
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientStop {
|
||||||
|
position: 1
|
||||||
|
color: "#0f212e"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: bgTopBar.bottom
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
id: flickable
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 15
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: cellWidth * 3
|
||||||
|
cellHeight: 145
|
||||||
|
cellWidth: 145
|
||||||
|
model: tabletProxy.buttons
|
||||||
|
delegate: Item {
|
||||||
|
width: flickable.cellWidth
|
||||||
|
height: flickable.cellHeight
|
||||||
|
property var proxy: modelData
|
||||||
|
|
||||||
|
TabletButton {
|
||||||
|
id: tabletButton
|
||||||
|
anchors.centerIn: parent
|
||||||
|
onClicked: modelData.clicked()
|
||||||
|
state: wrapper.GridView.isCurrentItem ? "hover state" : "base state"
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: modelData;
|
||||||
|
onPropertiesChanged: {
|
||||||
|
updateProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: updateProperties()
|
||||||
|
|
||||||
|
function updateProperties() {
|
||||||
|
var keys = Object.keys(modelData.properties).forEach(function (key) {
|
||||||
|
if (tabletButton[key] !== modelData.properties[key]) {
|
||||||
|
tabletButton[key] = modelData.properties[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onRightPressed: flickable.moveCurrentIndexRight();
|
||||||
|
Keys.onLeftPressed: flickable.moveCurrentIndexLeft();
|
||||||
|
Keys.onDownPressed: flickable.moveCurrentIndexDown();
|
||||||
|
Keys.onUpPressed: flickable.moveCurrentIndexUp();
|
||||||
|
Keys.onReturnPressed: {
|
||||||
|
if (flickable.currentItem) {
|
||||||
|
flickable.currentItem.proxy.clicked();
|
||||||
|
if (tabletRoot) {
|
||||||
|
tabletRoot.playButtonClickSound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,12 +77,12 @@ FocusScope {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onEntered: {
|
onEntered: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
listView.currentIndex = index
|
listView.currentIndex = index
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
root.selected(item);
|
root.selected(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,37 +68,36 @@ Item {
|
||||||
|
|
||||||
function loadSource(url) {
|
function loadSource(url) {
|
||||||
tabletApps.clear();
|
tabletApps.clear();
|
||||||
loader.source = ""; // make sure we load the qml fresh each time.
|
|
||||||
loader.source = url;
|
|
||||||
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
||||||
|
loader.load(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadQMLOnTop(url) {
|
function loadQMLOnTop(url) {
|
||||||
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
||||||
loader.source = "";
|
loader.load(tabletApps.get(currentApp).appUrl, function(){
|
||||||
loader.source = tabletApps.get(currentApp).appUrl;
|
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
||||||
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
loader.item.gotoPreviousApp = true;
|
||||||
loader.item.gotoPreviousApp = true;
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadWebOnTop(url, injectJavaScriptUrl) {
|
function loadWebContent(source, url, injectJavaScriptUrl) {
|
||||||
tabletApps.append({"appUrl": loader.source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url});
|
tabletApps.append({"appUrl": source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url});
|
||||||
loader.item.url = tabletApps.get(currentApp).appWebUrl;
|
loader.load(source, function() {
|
||||||
loader.item.scriptUrl = tabletApps.get(currentApp).scriptUrl;
|
loader.item.scriptURL = injectJavaScriptUrl;
|
||||||
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
loader.item.url = url;
|
||||||
loader.item.gotoPreviousApp = true;
|
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
||||||
}
|
loader.item.gotoPreviousApp = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadWebBase() {
|
function loadWebBase(url, injectJavaScriptUrl) {
|
||||||
loader.source = "";
|
loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl);
|
||||||
loader.source = "TabletWebView.qml";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadTabletWebBase() {
|
function loadTabletWebBase(url, injectJavaScriptUrl) {
|
||||||
loader.source = "";
|
loadWebContent("hifi/tablet/BlocksWebView.qml", url, injectJavaScriptUrl);
|
||||||
loader.source = "./BlocksWebView.qml";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function returnToPreviousApp() {
|
function returnToPreviousApp() {
|
||||||
|
@ -110,7 +109,7 @@ Item {
|
||||||
loadSource("TabletWebView.qml");
|
loadSource("TabletWebView.qml");
|
||||||
loadWebUrl(webUrl, scriptUrl);
|
loadWebUrl(webUrl, scriptUrl);
|
||||||
} else {
|
} else {
|
||||||
loader.source = tabletApps.get(currentApp).appUrl;
|
loader.load(tabletApps.get(currentApp).appUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,47 +172,79 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
// Hook up callback for clara.io download from the marketplace.
|
||||||
id: loader
|
Connections {
|
||||||
objectName: "loader"
|
id: eventBridgeConnection
|
||||||
asynchronous: false
|
target: eventBridge
|
||||||
|
onWebEventReceived: {
|
||||||
width: parent.width
|
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||||
height: parent.height
|
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||||
|
|
||||||
// Hook up callback for clara.io download from the marketplace.
|
|
||||||
Connections {
|
|
||||||
id: eventBridgeConnection
|
|
||||||
target: eventBridge
|
|
||||||
onWebEventReceived: {
|
|
||||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
|
||||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onLoaded: {
|
|
||||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
|
||||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
|
||||||
}
|
|
||||||
if (loader.item.hasOwnProperty("setRootMenu")) {
|
|
||||||
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
|
||||||
}
|
|
||||||
loader.item.forceActiveFocus();
|
|
||||||
|
|
||||||
if (openModal) {
|
|
||||||
openModal.canceled();
|
|
||||||
openModal.destroy();
|
|
||||||
openModal = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (openBrowser) {
|
|
||||||
openBrowser.destroy();
|
|
||||||
openBrowser = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: loader
|
||||||
|
objectName: "loader";
|
||||||
|
anchors.fill: parent;
|
||||||
|
property string source: "";
|
||||||
|
property var item: null;
|
||||||
|
signal loaded;
|
||||||
|
|
||||||
|
onWidthChanged: {
|
||||||
|
if (loader.item) {
|
||||||
|
loader.item.width = loader.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onHeightChanged: {
|
||||||
|
if (loader.item) {
|
||||||
|
loader.item.height = loader.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function load(newSource, callback) {
|
||||||
|
if (loader.source == newSource) {
|
||||||
|
loader.loaded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loader.item) {
|
||||||
|
loader.item.destroy();
|
||||||
|
loader.item = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlSurface.load(newSource, loader, function(newItem) {
|
||||||
|
loader.item = newItem;
|
||||||
|
loader.item.width = loader.width;
|
||||||
|
loader.item.height = loader.height;
|
||||||
|
loader.loaded();
|
||||||
|
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||||
|
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||||
|
}
|
||||||
|
if (loader.item.hasOwnProperty("setRootMenu")) {
|
||||||
|
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||||
|
}
|
||||||
|
loader.item.forceActiveFocus();
|
||||||
|
|
||||||
|
if (openModal) {
|
||||||
|
openModal.canceled();
|
||||||
|
openModal.destroy();
|
||||||
|
openModal = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openBrowser) {
|
||||||
|
openBrowser.destroy();
|
||||||
|
openBrowser = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
width: 480
|
width: 480
|
||||||
height: 706
|
height: 706
|
||||||
|
|
||||||
|
|
|
@ -59,26 +59,25 @@ Windows.ScrollingWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSource(url) {
|
function loadSource(url) {
|
||||||
loader.source = ""; // make sure we load the qml fresh each time.
|
loader.load(url)
|
||||||
loader.source = url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadWebBase() {
|
function loadWebContent(source, url, injectJavaScriptUrl) {
|
||||||
loader.source = "";
|
loader.load(source, function() {
|
||||||
loader.source = "WindowWebView.qml";
|
loader.item.scriptURL = injectJavaScriptUrl;
|
||||||
|
loader.item.url = url;
|
||||||
|
if (loader.item.hasOwnProperty("closeButtonVisible")) {
|
||||||
|
loader.item.closeButtonVisible = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadTabletWebBase() {
|
function loadWebBase(url, injectJavaScriptUrl) {
|
||||||
loader.source = "";
|
loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl);
|
||||||
loader.source = "./BlocksWebView.qml";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadWebUrl(url, injectedJavaScriptUrl) {
|
function loadTabletWebBase(url, injectJavaScriptUrl) {
|
||||||
loader.item.url = url;
|
loadWebContent("hifi/tablet/BlocksWebView.qml", url, injectJavaScriptUrl);
|
||||||
loader.item.scriptURL = injectedJavaScriptUrl;
|
|
||||||
if (loader.item.hasOwnProperty("closeButtonVisible")) {
|
|
||||||
loader.item.closeButtonVisible = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// used to send a message from qml to interface script.
|
// used to send a message from qml to interface script.
|
||||||
|
@ -111,38 +110,68 @@ Windows.ScrollingWindow {
|
||||||
username = newUsername;
|
username = newUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
// Hook up callback for clara.io download from the marketplace.
|
||||||
|
Connections {
|
||||||
|
id: eventBridgeConnection
|
||||||
|
target: eventBridge
|
||||||
|
onWebEventReceived: {
|
||||||
|
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||||
|
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
id: loader
|
id: loader
|
||||||
objectName: "loader"
|
objectName: "loader";
|
||||||
asynchronous: false
|
property string source: "";
|
||||||
|
property var item: null;
|
||||||
|
|
||||||
height: pane.scrollHeight
|
height: pane.scrollHeight
|
||||||
width: pane.contentWidth
|
width: pane.contentWidth
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
signal loaded;
|
||||||
// Hook up callback for clara.io download from the marketplace.
|
|
||||||
Connections {
|
onWidthChanged: {
|
||||||
id: eventBridgeConnection
|
if (loader.item) {
|
||||||
target: eventBridge
|
loader.item.width = loader.width;
|
||||||
onWebEventReceived: {
|
|
||||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
|
||||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
onHeightChanged: {
|
||||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
if (loader.item) {
|
||||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
loader.item.height = loader.height;
|
||||||
}
|
}
|
||||||
if (loader.item.hasOwnProperty("setRootMenu")) {
|
}
|
||||||
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
|
||||||
|
function load(newSource, callback) {
|
||||||
|
if (loader.item) {
|
||||||
|
loader.item.destroy();
|
||||||
|
loader.item = null;
|
||||||
}
|
}
|
||||||
loader.item.forceActiveFocus();
|
|
||||||
|
QmlSurface.load(newSource, loader, function(newItem) {
|
||||||
|
loader.item = newItem;
|
||||||
|
loader.item.width = loader.width;
|
||||||
|
loader.item.height = loader.height;
|
||||||
|
loader.loaded();
|
||||||
|
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||||
|
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||||
|
}
|
||||||
|
if (loader.item.hasOwnProperty("setRootMenu")) {
|
||||||
|
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||||
|
}
|
||||||
|
loader.item.forceActiveFocus();
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
implicitWidth: 480
|
implicitWidth: 480
|
||||||
implicitHeight: 706
|
implicitHeight: 706
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ Window {
|
||||||
horizontalSpacers: horizontal
|
horizontalSpacers: horizontal
|
||||||
verticalSpacers: !horizontal
|
verticalSpacers: !horizontal
|
||||||
}
|
}
|
||||||
|
property var tabletProxy;
|
||||||
|
property var buttonModel: ListModel {}
|
||||||
hideBackground: true
|
hideBackground: true
|
||||||
resizable: false
|
resizable: false
|
||||||
destroyOnCloseButton: false
|
destroyOnCloseButton: false
|
||||||
|
@ -23,24 +25,32 @@ Window {
|
||||||
activator: Item {}
|
activator: Item {}
|
||||||
property bool horizontal: true
|
property bool horizontal: true
|
||||||
property real buttonSize: 50;
|
property real buttonSize: 50;
|
||||||
property var buttons: []
|
|
||||||
property var container: horizontal ? row : column
|
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
category: "toolbar/" + window.objectName
|
category: "toolbar/" + window.objectName
|
||||||
property alias x: window.x
|
property alias x: window.x
|
||||||
property alias y: window.y
|
property alias y: window.y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: buttonComponent
|
||||||
|
ToolbarButton {
|
||||||
|
id: toolbarButton
|
||||||
|
property var proxy: modelData;
|
||||||
|
onClicked: proxy.clicked()
|
||||||
|
Component.onCompleted: updateProperties()
|
||||||
|
|
||||||
onHorizontalChanged: {
|
Connections {
|
||||||
var newParent = horizontal ? row : column;
|
target: proxy;
|
||||||
for (var i in buttons) {
|
onPropertiesChanged: updateProperties();
|
||||||
var child = buttons[i];
|
}
|
||||||
child.parent = newParent;
|
|
||||||
if (horizontal) {
|
function updateProperties() {
|
||||||
child.y = 0
|
Object.keys(proxy.properties).forEach(function (key) {
|
||||||
} else {
|
if (toolbarButton[key] !== proxy.properties[key]) {
|
||||||
child.x = 0
|
toolbarButton[key] = proxy.properties[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,97 +62,22 @@ Window {
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: row
|
id: row
|
||||||
|
visible: window.horizontal
|
||||||
spacing: 6
|
spacing: 6
|
||||||
|
Repeater {
|
||||||
|
model: buttonModel
|
||||||
|
delegate: buttonComponent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: column
|
id: column
|
||||||
|
visible: !window.horizontal
|
||||||
spacing: 6
|
spacing: 6
|
||||||
}
|
Repeater {
|
||||||
|
model: buttonModel
|
||||||
Component { id: toolbarButtonBuilder; ToolbarButton { } }
|
delegate: buttonComponent
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function findButtonIndex(name) {
|
|
||||||
if (!name) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i in buttons) {
|
|
||||||
var child = buttons[i];
|
|
||||||
if (child.objectName === name) {
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function findButton(name) {
|
|
||||||
var index = findButtonIndex(name);
|
|
||||||
if (index < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return buttons[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortButtons() {
|
|
||||||
var children = [];
|
|
||||||
for (var i = 0; i < container.children.length; i++) {
|
|
||||||
children[i] = container.children[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
children.sort(function (a, b) {
|
|
||||||
if (a.sortOrder === b.sortOrder) {
|
|
||||||
// subsort by stableOrder, because JS sort is not stable in qml.
|
|
||||||
return a.stableOrder - b.stableOrder;
|
|
||||||
} else {
|
|
||||||
return a.sortOrder - b.sortOrder;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
container.children = children;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addButton(properties) {
|
|
||||||
properties = properties || {}
|
|
||||||
|
|
||||||
// If a name is specified, then check if there's an existing button with that name
|
|
||||||
// and return it if so. This will allow multiple clients to listen to a single button,
|
|
||||||
// and allow scripts to be idempotent so they don't duplicate buttons if they're reloaded
|
|
||||||
var result = findButton(properties.objectName);
|
|
||||||
if (result) {
|
|
||||||
for (var property in properties) {
|
|
||||||
result[property] = properties[property];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
properties.toolbar = this;
|
|
||||||
properties.opacity = 0;
|
|
||||||
result = toolbarButtonBuilder.createObject(container, properties);
|
|
||||||
buttons.push(result);
|
|
||||||
|
|
||||||
result.opacity = 1;
|
|
||||||
|
|
||||||
sortButtons();
|
|
||||||
|
|
||||||
fadeIn(null);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeButton(name) {
|
|
||||||
var index = findButtonIndex(name);
|
|
||||||
if (index < -1) {
|
|
||||||
console.warn("Tried to remove non-existent button " + name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons[index].destroy();
|
|
||||||
buttons.splice(index, 1);
|
|
||||||
|
|
||||||
if (buttons.length === 0) {
|
|
||||||
fadeOut(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@ StateImage {
|
||||||
property string activeHoverIcon: button.activeIcon
|
property string activeHoverIcon: button.activeIcon
|
||||||
|
|
||||||
property int sortOrder: 100
|
property int sortOrder: 100
|
||||||
property int stableSortOrder: 0
|
property int stableOrder: 0
|
||||||
|
property var uuid;
|
||||||
|
|
||||||
signal clicked()
|
signal clicked()
|
||||||
|
|
||||||
|
|
BIN
interface/resources/qml/js/Utils.jsc
Normal file
|
@ -1496,6 +1496,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(getEntities()->getTree().get(), &EntityTree::deletingEntity, [=](const EntityItemID& entityItemID) {
|
||||||
|
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||||
|
auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr;
|
||||||
|
if (myAvatar) {
|
||||||
|
myAvatar->clearAvatarEntity(entityItemID);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Keyboard focus handling for Web overlays.
|
// Keyboard focus handling for Web overlays.
|
||||||
auto overlays = &(qApp->getOverlays());
|
auto overlays = &(qApp->getOverlays());
|
||||||
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {
|
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {
|
||||||
|
@ -2240,27 +2248,65 @@ extern void setupPreferences();
|
||||||
void Application::initializeUi() {
|
void Application::initializeUi() {
|
||||||
// Make sure all QML surfaces share the main thread GL context
|
// Make sure all QML surfaces share the main thread GL context
|
||||||
OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext());
|
OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext());
|
||||||
|
OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "OverlayWindowTest.qml" },
|
||||||
|
[](QQmlContext* context) {
|
||||||
|
qDebug() << "Whitelist OverlayWindow worked";
|
||||||
|
context->setContextProperty("OverlayWindowTestString", "TestWorked");
|
||||||
|
});
|
||||||
|
OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "hifi/audio/Audio.qml" },
|
||||||
|
[](QQmlContext* context) {
|
||||||
|
qDebug() << "QQQ" << __FUNCTION__ << "Whitelist Audio worked";
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
AddressBarDialog::registerType();
|
AddressBarDialog::registerType();
|
||||||
ErrorDialog::registerType();
|
ErrorDialog::registerType();
|
||||||
LoginDialog::registerType();
|
LoginDialog::registerType();
|
||||||
Tooltip::registerType();
|
Tooltip::registerType();
|
||||||
UpdateDialog::registerType();
|
UpdateDialog::registerType();
|
||||||
QmlCommerce::registerType();
|
QmlContextCallback callback = [](QQmlContext* context) {
|
||||||
|
context->setContextProperty("Commerce", new QmlCommerce());
|
||||||
|
};
|
||||||
|
OffscreenQmlSurface::addWhitelistContextHandler({
|
||||||
|
QUrl{ "hifi/commerce/checkout/Checkout.qml" },
|
||||||
|
QUrl{ "hifi/commerce/common/CommerceLightbox.qml" },
|
||||||
|
QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" },
|
||||||
|
QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" },
|
||||||
|
QUrl{ "hifi/commerce/common/SortableListModel.qml" },
|
||||||
|
QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" },
|
||||||
|
QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" },
|
||||||
|
QUrl{ "hifi/commerce/purchases/Purchases.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/Help.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/NeedsLogIn.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/Security.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/SendMoney.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/Wallet.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/WalletHome.qml" },
|
||||||
|
QUrl{ "hifi/commerce/wallet/WalletSetup.qml" },
|
||||||
|
}, callback);
|
||||||
qmlRegisterType<ResourceImageItem>("Hifi", 1, 0, "ResourceImageItem");
|
qmlRegisterType<ResourceImageItem>("Hifi", 1, 0, "ResourceImageItem");
|
||||||
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
|
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
|
||||||
qmlRegisterType<WebBrowserSuggestionsEngine>("HifiWeb", 1, 0, "WebBrowserSuggestionsEngine");
|
qmlRegisterType<WebBrowserSuggestionsEngine>("HifiWeb", 1, 0, "WebBrowserSuggestionsEngine");
|
||||||
|
|
||||||
|
{
|
||||||
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
tabletScriptingInterface->getTablet(SYSTEM_TABLET);
|
||||||
|
}
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->create();
|
offscreenUi->create();
|
||||||
|
|
||||||
auto surfaceContext = offscreenUi->getSurfaceContext();
|
auto surfaceContext = offscreenUi->getSurfaceContext();
|
||||||
|
|
||||||
offscreenUi->setProxyWindow(_window->windowHandle());
|
offscreenUi->setProxyWindow(_window->windowHandle());
|
||||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
|
||||||
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
|
// OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to
|
||||||
// support the window management and scripting proxies for VR use
|
// support the window management and scripting proxies for VR use
|
||||||
offscreenUi->createDesktop(QString("qrc:///qml/hifi/Desktop.qml"));
|
offscreenUi->createDesktop(QString("hifi/Desktop.qml"));
|
||||||
|
|
||||||
// FIXME either expose so that dialogs can set this themselves or
|
// FIXME either expose so that dialogs can set this themselves or
|
||||||
// do better detection in the offscreen UI of what has focus
|
// do better detection in the offscreen UI of what has focus
|
||||||
|
@ -2328,9 +2374,6 @@ void Application::initializeUi() {
|
||||||
surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
|
surfaceContext->setContextProperty("InputConfiguration", DependencyManager::get<InputConfiguration>().data());
|
||||||
|
|
||||||
surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
surfaceContext->setContextProperty("Account", AccountScriptingInterface::getInstance());
|
||||||
surfaceContext->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
|
||||||
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
|
|
||||||
surfaceContext->setContextProperty("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
|
|
||||||
surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
|
surfaceContext->setContextProperty("DialogsManager", _dialogsManagerScriptingInterface);
|
||||||
surfaceContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
surfaceContext->setContextProperty("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||||
surfaceContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
|
surfaceContext->setContextProperty("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
|
||||||
|
@ -3222,8 +3265,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Application::keyReleaseEvent(QKeyEvent* event) {
|
void Application::keyReleaseEvent(QKeyEvent* event) {
|
||||||
_keysPressed.remove(event->key());
|
_keysPressed.remove(event->key());
|
||||||
|
|
||||||
|
@ -4282,9 +4323,11 @@ void Application::updateLOD(float deltaTime) const {
|
||||||
PerformanceTimer perfTimer("LOD");
|
PerformanceTimer perfTimer("LOD");
|
||||||
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
||||||
if (!isThrottleRendering()) {
|
if (!isThrottleRendering()) {
|
||||||
float batchTime = (float)_gpuContext->getFrameTimerBatchAverage();
|
float presentTime = getActiveDisplayPlugin()->getAveragePresentTime();
|
||||||
float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime());
|
float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime());
|
||||||
DependencyManager::get<LODManager>()->autoAdjustLOD(batchTime, engineRunTime, deltaTime);
|
float gpuTime = getGPUContext()->getFrameTimerGPUAverage();
|
||||||
|
float maxRenderTime = glm::max(gpuTime, glm::max(presentTime, engineRunTime));
|
||||||
|
DependencyManager::get<LODManager>()->autoAdjustLOD(maxRenderTime, deltaTime);
|
||||||
} else {
|
} else {
|
||||||
DependencyManager::get<LODManager>()->resetLODAdjust();
|
DependencyManager::get<LODManager>()->resetLODAdjust();
|
||||||
}
|
}
|
||||||
|
@ -4848,8 +4891,7 @@ void Application::update(float deltaTime) {
|
||||||
if (_physicsEnabled) {
|
if (_physicsEnabled) {
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "PreStep");
|
PROFILE_RANGE(simulation_physics, "PreStep");
|
||||||
|
PerformanceTimer perfTimer("preStep)");
|
||||||
PerformanceTimer perfTimer("updateStates)");
|
|
||||||
static VectorOfMotionStates motionStates;
|
static VectorOfMotionStates motionStates;
|
||||||
_entitySimulation->getObjectsToRemoveFromPhysics(motionStates);
|
_entitySimulation->getObjectsToRemoveFromPhysics(motionStates);
|
||||||
_physicsEngine->removeObjects(motionStates);
|
_physicsEngine->removeObjects(motionStates);
|
||||||
|
@ -4882,22 +4924,22 @@ void Application::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "Step");
|
PROFILE_RANGE(simulation_physics, "Step");
|
||||||
PerformanceTimer perfTimer("stepSimulation");
|
PerformanceTimer perfTimer("step");
|
||||||
getEntities()->getTree()->withWriteLock([&] {
|
getEntities()->getTree()->withWriteLock([&] {
|
||||||
_physicsEngine->stepSimulation();
|
_physicsEngine->stepSimulation();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "PostStep");
|
PROFILE_RANGE(simulation_physics, "PostStep");
|
||||||
PerformanceTimer perfTimer("harvestChanges");
|
PerformanceTimer perfTimer("postStep");
|
||||||
if (_physicsEngine->hasOutgoingChanges()) {
|
if (_physicsEngine->hasOutgoingChanges()) {
|
||||||
// grab the collision events BEFORE handleOutgoingChanges() because at this point
|
// grab the collision events BEFORE handleOutgoingChanges() because at this point
|
||||||
// we have a better idea of which objects we own or should own.
|
// we have a better idea of which objects we own or should own.
|
||||||
auto& collisionEvents = _physicsEngine->getCollisionEvents();
|
auto& collisionEvents = _physicsEngine->getCollisionEvents();
|
||||||
|
|
||||||
getEntities()->getTree()->withWriteLock([&] {
|
getEntities()->getTree()->withWriteLock([&] {
|
||||||
PROFILE_RANGE(simulation_physics, "Harvest");
|
PROFILE_RANGE(simulation_physics, "HandleChanges");
|
||||||
PerformanceTimer perfTimer("handleOutgoingChanges");
|
PerformanceTimer perfTimer("handleChanges");
|
||||||
|
|
||||||
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
|
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
|
||||||
_entitySimulation->handleChangedMotionStates(outgoingChanges);
|
_entitySimulation->handleChangedMotionStates(outgoingChanges);
|
||||||
|
@ -4908,17 +4950,15 @@ void Application::update(float deltaTime) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!_aboutToQuit) {
|
if (!_aboutToQuit) {
|
||||||
// handleCollisionEvents() AFTER handleOutgoinChanges()
|
// handleCollisionEvents() AFTER handleOutgoingChanges()
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(simulation_physics, "CollisionEvents");
|
PROFILE_RANGE(simulation_physics, "CollisionEvents");
|
||||||
PerformanceTimer perfTimer("entities");
|
|
||||||
avatarManager->handleCollisionEvents(collisionEvents);
|
avatarManager->handleCollisionEvents(collisionEvents);
|
||||||
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
|
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk
|
||||||
// deadlock.)
|
// deadlock.)
|
||||||
_entitySimulation->handleCollisionEvents(collisionEvents);
|
_entitySimulation->handleCollisionEvents(collisionEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
PROFILE_RANGE(simulation_physics, "UpdateEntities");
|
|
||||||
// NOTE: the getEntities()->update() call below will wait for lock
|
// NOTE: the getEntities()->update() call below will wait for lock
|
||||||
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
|
||||||
getEntities()->update(true); // update the models...
|
getEntities()->update(true); // update the models...
|
||||||
|
@ -4929,7 +4969,8 @@ void Application::update(float deltaTime) {
|
||||||
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
|
myAvatar->harvestResultsFromPhysicsSimulation(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
|
if (PerformanceTimer::isActive() &&
|
||||||
|
Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) &&
|
||||||
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
|
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) {
|
||||||
_physicsEngine->harvestPerformanceStats();
|
_physicsEngine->harvestPerformanceStats();
|
||||||
}
|
}
|
||||||
|
@ -5832,9 +5873,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
||||||
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<TabletProxy>, wrapperFromScriptValue<TabletProxy>);
|
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<TabletProxy>, wrapperFromScriptValue<TabletProxy>);
|
||||||
qScriptRegisterMetaType(scriptEngine.data(),
|
qScriptRegisterMetaType(scriptEngine.data(),
|
||||||
wrapperToScriptValue<TabletButtonProxy>, wrapperFromScriptValue<TabletButtonProxy>);
|
wrapperToScriptValue<TabletButtonProxy>, wrapperFromScriptValue<TabletButtonProxy>);
|
||||||
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
|
|
||||||
scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
|
|
||||||
scriptEngine->registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
scriptEngine->registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||||
|
// FIXME remove these deprecated names for the tablet scripting interface
|
||||||
|
scriptEngine->registerGlobalObject("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
|
||||||
|
|
||||||
auto toolbarScriptingInterface = DependencyManager::get<ToolbarScriptingInterface>().data();
|
auto toolbarScriptingInterface = DependencyManager::get<ToolbarScriptingInterface>().data();
|
||||||
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(toolbarScriptingInterface);
|
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(toolbarScriptingInterface);
|
||||||
|
@ -7241,13 +7282,17 @@ void Application::updateDisplayMode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
|
auto desktop = offscreenUi->getDesktop();
|
||||||
|
|
||||||
// Make the switch atomic from the perspective of other threads
|
// Make the switch atomic from the perspective of other threads
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(_displayPluginLock);
|
std::unique_lock<std::mutex> lock(_displayPluginLock);
|
||||||
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
|
bool wasRepositionLocked = false;
|
||||||
bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
|
if (desktop) {
|
||||||
offscreenUi->getDesktop()->setProperty("repositionLocked", true);
|
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
|
||||||
|
wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
|
||||||
|
offscreenUi->getDesktop()->setProperty("repositionLocked", true);
|
||||||
|
}
|
||||||
|
|
||||||
if (_displayPlugin) {
|
if (_displayPlugin) {
|
||||||
disconnect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
|
disconnect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent);
|
||||||
|
@ -7293,7 +7338,6 @@ void Application::updateDisplayMode() {
|
||||||
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
|
getApplicationCompositor().setDisplayPlugin(newDisplayPlugin);
|
||||||
_displayPlugin = newDisplayPlugin;
|
_displayPlugin = newDisplayPlugin;
|
||||||
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection);
|
connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection);
|
||||||
auto desktop = offscreenUi->getDesktop();
|
|
||||||
if (desktop) {
|
if (desktop) {
|
||||||
desktop->setProperty("repositionLocked", wasRepositionLocked);
|
desktop->setProperty("repositionLocked", wasRepositionLocked);
|
||||||
}
|
}
|
||||||
|
@ -7506,4 +7550,9 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) {
|
||||||
_avatarOverrideUrl = url;
|
_avatarOverrideUrl = url;
|
||||||
_saveAvatarOverrideUrl = save;
|
_saveAvatarOverrideUrl = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::saveNextPhysicsStats(QString filename) {
|
||||||
|
_physicsEngine->saveNextPhysicsStats(filename);
|
||||||
|
}
|
||||||
|
|
||||||
#include "Application.moc"
|
#include "Application.moc"
|
||||||
|
|
|
@ -280,6 +280,7 @@ public:
|
||||||
void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; }
|
void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; }
|
||||||
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
|
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
|
||||||
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
|
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
|
||||||
|
void saveNextPhysicsStats(QString filename);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void svoImportRequested(const QString& url);
|
void svoImportRequested(const QString& url);
|
||||||
|
@ -432,6 +433,7 @@ private slots:
|
||||||
|
|
||||||
void handleSandboxStatus(QNetworkReply* reply);
|
void handleSandboxStatus(QNetworkReply* reply);
|
||||||
void switchDisplayMode();
|
void switchDisplayMode();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void initDisplay();
|
static void initDisplay();
|
||||||
void init();
|
void init();
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "LODManager.h"
|
#include "LODManager.h"
|
||||||
|
|
||||||
|
|
||||||
Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS);
|
Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS);
|
||||||
Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS);
|
Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS);
|
||||||
|
|
||||||
|
@ -39,156 +40,95 @@ float LODManager::getLODIncreaseFPS() {
|
||||||
return getDesktopLODIncreaseFPS();
|
return getDesktopLODIncreaseFPS();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LODManager::autoAdjustLOD(float batchTime, float engineRunTime, float deltaTimeSec) {
|
// We use a "time-weighted running average" of the renderTime and compare it against min/max thresholds
|
||||||
|
// to determine if we should adjust the level of detail (LOD).
|
||||||
|
//
|
||||||
|
// A time-weighted running average has a timescale which determines how fast the average tracks the measured
|
||||||
|
// value in real-time. Given a step-function in the mesured value, and assuming measurements happen
|
||||||
|
// faster than the runningAverage is computed, the error between the value and its runningAverage will be
|
||||||
|
// reduced by 1/e every timescale of real-time that passes.
|
||||||
|
const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.1f; // sec
|
||||||
|
//
|
||||||
|
// Assuming the measured value is affected by logic invoked by the runningAverage bumping up against its
|
||||||
|
// thresholds, we expect the adjustment to introduce a step-function. We want the runningAverage settle
|
||||||
|
// to the new value BEFORE we test it aginst its thresholds again. Hence we test on a period that is a few
|
||||||
|
// multiples of the running average timescale:
|
||||||
|
const uint64_t LOD_AUTO_ADJUST_PERIOD = 5 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec
|
||||||
|
|
||||||
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
|
const float LOD_AUTO_ADJUST_DECREMENT_FACTOR = 0.8f;
|
||||||
// really want to count them in our average, so we will ignore the real frame rates and stuff
|
const float LOD_AUTO_ADJUST_INCREMENT_FACTOR = 1.2f;
|
||||||
// our moving average with simulated good data
|
|
||||||
const int IGNORE_THESE_SAMPLES = 100;
|
|
||||||
if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) {
|
|
||||||
_lastStable = _lastUpShift = _lastDownShift = usecTimestampNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) {
|
||||||
// compute time-weighted running average renderTime
|
// compute time-weighted running average renderTime
|
||||||
const float OVERLAY_AND_SWAP_TIME_BUDGET = 2.0f; // msec
|
// Note: we MUST clamp the blend to 1.0 for stability
|
||||||
float renderTime = batchTime + OVERLAY_AND_SWAP_TIME_BUDGET;
|
float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f;
|
||||||
float maxTime = glm::max(renderTime, engineRunTime);
|
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * renderTime; // msec
|
||||||
const float BLEND_TIMESCALE = 0.3f; // sec
|
if (!_automaticLODAdjust) {
|
||||||
const float MIN_DELTA_TIME = 0.001f;
|
// early exit
|
||||||
const float safeDeltaTime = glm::max(deltaTimeSec, MIN_DELTA_TIME);
|
return;
|
||||||
float blend = BLEND_TIMESCALE / safeDeltaTime;
|
|
||||||
if (blend > 1.0f) {
|
|
||||||
blend = 1.0f;
|
|
||||||
}
|
}
|
||||||
_avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxTime; // msec
|
|
||||||
|
|
||||||
// translate into fps for legacy implementation
|
float oldOctreeSizeScale = _octreeSizeScale;
|
||||||
float currentFPS = (float)MSECS_PER_SECOND / _avgRenderTime;
|
float currentFPS = (float)MSECS_PER_SECOND / _avgRenderTime;
|
||||||
|
uint64_t now = usecTimestampNow();
|
||||||
_fpsAverageStartWindow.updateAverage(currentFPS);
|
if (currentFPS < getLODDecreaseFPS()) {
|
||||||
_fpsAverageDownWindow.updateAverage(currentFPS);
|
if (now > _decreaseFPSExpiry) {
|
||||||
_fpsAverageUpWindow.updateAverage(currentFPS);
|
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
|
|
||||||
quint64 now = usecTimestampNow();
|
|
||||||
|
|
||||||
quint64 elapsedSinceDownShift = now - _lastDownShift;
|
|
||||||
quint64 elapsedSinceUpShift = now - _lastUpShift;
|
|
||||||
|
|
||||||
quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable);
|
|
||||||
quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift;
|
|
||||||
|
|
||||||
if (_automaticLODAdjust) {
|
|
||||||
bool changed = false;
|
|
||||||
|
|
||||||
// LOD Downward adjustment
|
|
||||||
// If we've been downshifting, we watch a shorter downshift window so that we will quickly move toward our
|
|
||||||
// target frame rate. But if we haven't just done a downshift (either because our last shift was an upshift,
|
|
||||||
// or because we've just started out) then we look at a much longer window to consider whether or not to start
|
|
||||||
// downshifting.
|
|
||||||
bool doDownShift = false;
|
|
||||||
|
|
||||||
if (_isDownshifting) {
|
|
||||||
// only consider things if our DOWN_SHIFT time has elapsed...
|
|
||||||
if (elapsedSinceDownShift > DOWN_SHIFT_ELPASED) {
|
|
||||||
doDownShift = _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS();
|
|
||||||
|
|
||||||
if (!doDownShift) {
|
|
||||||
qCDebug(interfaceapp) << "---- WE APPEAR TO BE DONE DOWN SHIFTING -----";
|
|
||||||
_isDownshifting = false;
|
|
||||||
_lastStable = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED
|
|
||||||
&& _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doDownShift) {
|
|
||||||
|
|
||||||
// Octree items... stepwise adjustment
|
|
||||||
if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
|
if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||||
_octreeSizeScale *= ADJUST_LOD_DOWN_BY;
|
_octreeSizeScale *= LOD_AUTO_ADJUST_DECREMENT_FACTOR;
|
||||||
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||||
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
||||||
}
|
}
|
||||||
changed = true;
|
qCDebug(interfaceapp) << "adjusting LOD DOWN"
|
||||||
}
|
<< "fps =" << currentFPS
|
||||||
|
<< "targetFPS =" << getLODDecreaseFPS()
|
||||||
if (changed) {
|
<< "octreeSizeScale =" << _octreeSizeScale;
|
||||||
if (_isDownshifting) {
|
|
||||||
// subsequent downshift
|
|
||||||
qCDebug(interfaceapp) << "adjusting LOD DOWN..."
|
|
||||||
<< "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was "
|
|
||||||
<< _fpsAverageDownWindow.getAverage()
|
|
||||||
<< "minimum is:" << getLODDecreaseFPS()
|
|
||||||
<< "elapsedSinceDownShift:" << elapsedSinceDownShift
|
|
||||||
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
|
||||||
} else {
|
|
||||||
// first downshift
|
|
||||||
qCDebug(interfaceapp) << "adjusting LOD DOWN after initial delay..."
|
|
||||||
<< "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was "
|
|
||||||
<< _fpsAverageStartWindow.getAverage()
|
|
||||||
<< "minimum is:" << getLODDecreaseFPS()
|
|
||||||
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
|
|
||||||
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastDownShift = now;
|
|
||||||
_isDownshifting = true;
|
|
||||||
|
|
||||||
emit LODDecreased();
|
emit LODDecreased();
|
||||||
}
|
}
|
||||||
} else {
|
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
|
|
||||||
// LOD Upward adjustment
|
|
||||||
if (elapsedSinceUpShift > UP_SHIFT_ELPASED) {
|
|
||||||
|
|
||||||
if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) {
|
|
||||||
|
|
||||||
// Octee items... stepwise adjustment
|
|
||||||
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
|
|
||||||
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
|
||||||
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
|
||||||
} else {
|
|
||||||
_octreeSizeScale *= ADJUST_LOD_UP_BY;
|
|
||||||
}
|
|
||||||
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
|
|
||||||
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
|
|
||||||
}
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
qCDebug(interfaceapp) << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was "
|
|
||||||
<< _fpsAverageUpWindow.getAverage()
|
|
||||||
<< "upshift point is:" << getLODIncreaseFPS()
|
|
||||||
<< "elapsedSinceUpShift:" << elapsedSinceUpShift
|
|
||||||
<< " NEW _octreeSizeScale=" << _octreeSizeScale;
|
|
||||||
|
|
||||||
_lastUpShift = now;
|
|
||||||
_isDownshifting = false;
|
|
||||||
|
|
||||||
emit LODIncreased();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
if (changed) {
|
} else if (currentFPS > getLODIncreaseFPS()) {
|
||||||
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
|
if (now > _increaseFPSExpiry) {
|
||||||
if (lodToolsDialog) {
|
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
lodToolsDialog->reloadSliders();
|
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
|
||||||
|
if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) {
|
||||||
|
_octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE;
|
||||||
|
} else {
|
||||||
|
_octreeSizeScale *= LOD_AUTO_ADJUST_INCREMENT_FACTOR;
|
||||||
|
}
|
||||||
|
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
|
||||||
|
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
|
||||||
|
}
|
||||||
|
qCDebug(interfaceapp) << "adjusting LOD UP"
|
||||||
|
<< "fps =" << currentFPS
|
||||||
|
<< "targetFPS =" << getLODDecreaseFPS()
|
||||||
|
<< "octreeSizeScale =" << _octreeSizeScale;
|
||||||
|
emit LODIncreased();
|
||||||
}
|
}
|
||||||
|
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
}
|
}
|
||||||
|
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
|
} else {
|
||||||
|
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
|
_decreaseFPSExpiry = _increaseFPSExpiry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldOctreeSizeScale != _octreeSizeScale) {
|
||||||
|
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
|
||||||
|
if (lodToolsDialog) {
|
||||||
|
lodToolsDialog->reloadSliders();
|
||||||
|
}
|
||||||
|
// Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime
|
||||||
|
// to be at middle of target zone. It will drift close to its true value within
|
||||||
|
// about three few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary.
|
||||||
|
float expectedFPS = 0.5f * (getLODIncreaseFPS() + getLODDecreaseFPS());
|
||||||
|
_avgRenderTime = MSECS_PER_SECOND / expectedFPS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LODManager::resetLODAdjust() {
|
void LODManager::resetLODAdjust() {
|
||||||
_fpsAverageStartWindow.reset();
|
_decreaseFPSExpiry = _increaseFPSExpiry = usecTimestampNow() + LOD_AUTO_ADJUST_PERIOD;
|
||||||
_fpsAverageDownWindow.reset();
|
|
||||||
_fpsAverageUpWindow.reset();
|
|
||||||
_lastUpShift = _lastDownShift = usecTimestampNow();
|
|
||||||
_isDownshifting = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const float MIN_DECREASE_FPS = 0.5f;
|
const float MIN_DECREASE_FPS = 0.5f;
|
||||||
|
@ -206,7 +146,7 @@ float LODManager::getDesktopLODDecreaseFPS() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
float LODManager::getDesktopLODIncreaseFPS() const {
|
float LODManager::getDesktopLODIncreaseFPS() const {
|
||||||
return glm::max(((float)MSECS_PER_SECOND / _desktopMaxRenderTime) + INCREASE_LOD_GAP, MAX_LIKELY_DESKTOP_FPS);
|
return glm::max(((float)MSECS_PER_SECOND / _desktopMaxRenderTime) + INCREASE_LOD_GAP_FPS, MAX_LIKELY_DESKTOP_FPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LODManager::setHMDLODDecreaseFPS(float fps) {
|
void LODManager::setHMDLODDecreaseFPS(float fps) {
|
||||||
|
@ -222,7 +162,7 @@ float LODManager::getHMDLODDecreaseFPS() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
float LODManager::getHMDLODIncreaseFPS() const {
|
float LODManager::getHMDLODIncreaseFPS() const {
|
||||||
return glm::max(((float)MSECS_PER_SECOND / _hmdMaxRenderTime) + INCREASE_LOD_GAP, MAX_LIKELY_HMD_FPS);
|
return glm::max(((float)MSECS_PER_SECOND / _hmdMaxRenderTime) + INCREASE_LOD_GAP_FPS, MAX_LIKELY_HMD_FPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LODManager::getLODFeedbackText() {
|
QString LODManager::getLODFeedbackText() {
|
||||||
|
|
|
@ -19,29 +19,13 @@
|
||||||
#include <SimpleMovingAverage.h>
|
#include <SimpleMovingAverage.h>
|
||||||
#include <render/Args.h>
|
#include <render/Args.h>
|
||||||
|
|
||||||
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 20.0;
|
const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0f;
|
||||||
const float DEFAULT_HMD_LOD_DOWN_FPS = 20.0;
|
const float DEFAULT_HMD_LOD_DOWN_FPS = 45.0f;
|
||||||
const float DEFAULT_DESKTOP_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_DESKTOP_LOD_DOWN_FPS; // msec
|
const float DEFAULT_DESKTOP_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_DESKTOP_LOD_DOWN_FPS; // msec
|
||||||
const float DEFAULT_HMD_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_HMD_LOD_DOWN_FPS; // msec
|
const float DEFAULT_HMD_MAX_RENDER_TIME = (float)MSECS_PER_SECOND / DEFAULT_HMD_LOD_DOWN_FPS; // msec
|
||||||
const float MAX_LIKELY_DESKTOP_FPS = 59.0; // this is essentially, V-synch - 1 fps
|
const float MAX_LIKELY_DESKTOP_FPS = 59.0f; // this is essentially, V-synch - 1 fps
|
||||||
const float MAX_LIKELY_HMD_FPS = 74.0; // this is essentially, V-synch - 1 fps
|
const float MAX_LIKELY_HMD_FPS = 74.0f; // this is essentially, V-synch - 1 fps
|
||||||
const float INCREASE_LOD_GAP = 15.0f;
|
const float INCREASE_LOD_GAP_FPS = 15.0f; // fps
|
||||||
|
|
||||||
const float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts
|
|
||||||
const float DOWN_SHIFT_WINDOW_IN_SECS = 0.5f;
|
|
||||||
const float UP_SHIFT_WINDOW_IN_SECS = 2.5f;
|
|
||||||
|
|
||||||
const int ASSUMED_FPS = 60;
|
|
||||||
const quint64 START_SHIFT_ELPASED = USECS_PER_SECOND * START_DELAY_WINDOW_IN_SECS;
|
|
||||||
const quint64 DOWN_SHIFT_ELPASED = USECS_PER_SECOND * DOWN_SHIFT_WINDOW_IN_SECS; // Consider adjusting LOD down after half a second
|
|
||||||
const quint64 UP_SHIFT_ELPASED = USECS_PER_SECOND * UP_SHIFT_WINDOW_IN_SECS;
|
|
||||||
|
|
||||||
const int START_DELAY_SAMPLES_OF_FRAMES = ASSUMED_FPS * START_DELAY_WINDOW_IN_SECS;
|
|
||||||
const int DOWN_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * DOWN_SHIFT_WINDOW_IN_SECS;
|
|
||||||
const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS;
|
|
||||||
|
|
||||||
const float ADJUST_LOD_DOWN_BY = 0.9f;
|
|
||||||
const float ADJUST_LOD_UP_BY = 1.1f;
|
|
||||||
|
|
||||||
// The default value DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision).
|
// The default value DEFAULT_OCTREE_SIZE_SCALE means you can be 400 meters away from a 1 meter object in order to see it (which is ~20:20 vision).
|
||||||
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
|
const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
|
||||||
|
@ -78,7 +62,7 @@ public:
|
||||||
Q_INVOKABLE float getLODIncreaseFPS();
|
Q_INVOKABLE float getLODIncreaseFPS();
|
||||||
|
|
||||||
static bool shouldRender(const RenderArgs* args, const AABox& bounds);
|
static bool shouldRender(const RenderArgs* args, const AABox& bounds);
|
||||||
void autoAdjustLOD(float batchTime, float engineRunTime, float deltaTimeSec);
|
void autoAdjustLOD(float renderTime, float realTimeDelta);
|
||||||
|
|
||||||
void loadSettings();
|
void loadSettings();
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
|
@ -92,21 +76,15 @@ private:
|
||||||
LODManager();
|
LODManager();
|
||||||
|
|
||||||
bool _automaticLODAdjust = true;
|
bool _automaticLODAdjust = true;
|
||||||
float _avgRenderTime { 0.0 };
|
float _avgRenderTime { 0.0f };
|
||||||
float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME };
|
float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME };
|
||||||
float _hmdMaxRenderTime { DEFAULT_HMD_MAX_RENDER_TIME };
|
float _hmdMaxRenderTime { DEFAULT_HMD_MAX_RENDER_TIME };
|
||||||
|
|
||||||
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
|
float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE;
|
||||||
int _boundaryLevelAdjust = 0;
|
int _boundaryLevelAdjust = 0;
|
||||||
|
|
||||||
quint64 _lastDownShift = 0;
|
uint64_t _decreaseFPSExpiry { 0 };
|
||||||
quint64 _lastUpShift = 0;
|
uint64_t _increaseFPSExpiry { 0 };
|
||||||
quint64 _lastStable = 0;
|
|
||||||
bool _isDownshifting = false; // start out as if we're not downshifting
|
|
||||||
|
|
||||||
SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES;
|
|
||||||
SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES;
|
|
||||||
SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_LODManager_h
|
#endif // hifi_LODManager_h
|
||||||
|
|
|
@ -101,7 +101,7 @@ Menu::Menu() {
|
||||||
auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J);
|
auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J);
|
||||||
connect(action, &QAction::triggered, [] {
|
connect(action, &QAction::triggered, [] {
|
||||||
static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml");
|
static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml");
|
||||||
static const QUrl tabletUrl("../../hifi/dialogs/TabletRunningScripts.qml");
|
static const QUrl tabletUrl("hifi/dialogs/TabletRunningScripts.qml");
|
||||||
static const QString name("RunningScripts");
|
static const QString name("RunningScripts");
|
||||||
qApp->showDialog(widgetUrl, tabletUrl, name);
|
qApp->showDialog(widgetUrl, tabletUrl, name);
|
||||||
});
|
});
|
||||||
|
@ -338,7 +338,7 @@ Menu::Menu() {
|
||||||
connect(action, &QAction::triggered, [] {
|
connect(action, &QAction::triggered, [] {
|
||||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||||
tablet->loadQMLSource("ControllerSettings.qml");
|
tablet->loadQMLSource("hifi/tablet/ControllerSettings.qml");
|
||||||
|
|
||||||
if (!hmd->getShouldShowTablet()) {
|
if (!hmd->getShouldShowTablet()) {
|
||||||
hmd->toggleShouldShowTablet();
|
hmd->toggleShouldShowTablet();
|
||||||
|
@ -645,7 +645,8 @@ Menu::Menu() {
|
||||||
// Developer > Timing >>>
|
// Developer > Timing >>>
|
||||||
MenuWrapper* timingMenu = developerMenu->addMenu("Timing");
|
MenuWrapper* timingMenu = developerMenu->addMenu("Timing");
|
||||||
MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
MenuWrapper* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayDebugTimingDetails, 0, false,
|
||||||
|
qApp, SLOT(enablePerfStats(bool)));
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::OnlyDisplayTopTen, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
||||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
|
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false);
|
||||||
|
|
|
@ -81,6 +81,7 @@ const QString& DEFAULT_AVATAR_COLLISION_SOUND_URL = "https://hifi-public.s3.amaz
|
||||||
const float MyAvatar::ZOOM_MIN = 0.5f;
|
const float MyAvatar::ZOOM_MIN = 0.5f;
|
||||||
const float MyAvatar::ZOOM_MAX = 25.0f;
|
const float MyAvatar::ZOOM_MAX = 25.0f;
|
||||||
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
||||||
|
const float MIN_SCALE_CHANGED_DELTA = 0.001f;
|
||||||
|
|
||||||
MyAvatar::MyAvatar(QThread* thread) :
|
MyAvatar::MyAvatar(QThread* thread) :
|
||||||
Avatar(thread),
|
Avatar(thread),
|
||||||
|
@ -670,6 +671,11 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
||||||
glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getWorldOrientation(), getWorldPosition());
|
glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getWorldOrientation(), getWorldPosition());
|
||||||
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
||||||
|
|
||||||
|
bool hasSensorToWorldScaleChanged = false;
|
||||||
|
if (fabsf(getSensorToWorldScale() - sensorToWorldScale) > MIN_SCALE_CHANGED_DELTA) {
|
||||||
|
hasSensorToWorldScaleChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
lateUpdatePalms();
|
lateUpdatePalms();
|
||||||
|
|
||||||
if (_enableDebugDrawSensorToWorldMatrix) {
|
if (_enableDebugDrawSensorToWorldMatrix) {
|
||||||
|
@ -678,9 +684,13 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
|
||||||
|
|
||||||
updateJointFromController(controller::Action::LEFT_HAND, _controllerLeftHandMatrixCache);
|
updateJointFromController(controller::Action::LEFT_HAND, _controllerLeftHandMatrixCache);
|
||||||
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
||||||
|
|
||||||
|
if (hasSensorToWorldScaleChanged) {
|
||||||
|
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update avatar head rotation with sensor data
|
// Update avatar head rotation with sensor data
|
||||||
|
@ -1405,6 +1415,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
_skeletonModel->setVisibleInScene(true, qApp->getMain3DScene());
|
||||||
_headBoneSet.clear();
|
_headBoneSet.clear();
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1440,6 +1451,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
|
||||||
UserActivityLogger::getInstance().changedModel("skeleton", urlString);
|
UserActivityLogger::getInstance().changedModel("skeleton", urlString);
|
||||||
}
|
}
|
||||||
markIdentityDataChanged();
|
markIdentityDataChanged();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
||||||
|
|
|
@ -9,9 +9,12 @@
|
||||||
#include "MySkeletonModel.h"
|
#include "MySkeletonModel.h"
|
||||||
|
|
||||||
#include <avatars-renderer/Avatar.h>
|
#include <avatars-renderer/Avatar.h>
|
||||||
|
#include <DebugDraw.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "InterfaceLogging.h"
|
#include "InterfaceLogging.h"
|
||||||
|
#include "AnimUtil.h"
|
||||||
|
|
||||||
|
|
||||||
MySkeletonModel::MySkeletonModel(Avatar* owningAvatar, QObject* parent) : SkeletonModel(owningAvatar, parent) {
|
MySkeletonModel::MySkeletonModel(Avatar* owningAvatar, QObject* parent) : SkeletonModel(owningAvatar, parent) {
|
||||||
}
|
}
|
||||||
|
@ -30,6 +33,39 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
|
||||||
|
glm::mat4 hipsMat = myAvatar->deriveBodyFromHMDSensor();
|
||||||
|
glm::vec3 hipsPos = extractTranslation(hipsMat);
|
||||||
|
glm::quat hipsRot = glmExtractRotation(hipsMat);
|
||||||
|
|
||||||
|
glm::mat4 avatarToWorldMat = myAvatar->getTransform().getMatrix();
|
||||||
|
glm::mat4 worldToSensorMat = glm::inverse(myAvatar->getSensorToWorldMatrix());
|
||||||
|
glm::mat4 avatarToSensorMat = worldToSensorMat * avatarToWorldMat;
|
||||||
|
|
||||||
|
// dampen hips rotation, by mixing it with the avatar orientation in sensor space
|
||||||
|
const float MIX_RATIO = 0.5f;
|
||||||
|
hipsRot = safeLerp(glmExtractRotation(avatarToSensorMat), hipsRot, MIX_RATIO);
|
||||||
|
|
||||||
|
if (isFlying) {
|
||||||
|
// rotate the hips back to match the flying animation.
|
||||||
|
|
||||||
|
const float TILT_ANGLE = 0.523f;
|
||||||
|
const glm::quat tiltRot = glm::angleAxis(TILT_ANGLE, transformVectorFast(avatarToSensorMat, -Vectors::UNIT_X));
|
||||||
|
|
||||||
|
glm::vec3 headPos;
|
||||||
|
int headIndex = myAvatar->getJointIndex("Head");
|
||||||
|
if (headIndex != -1) {
|
||||||
|
headPos = transformPoint(avatarToSensorMat, myAvatar->getAbsoluteJointTranslationInObjectFrame(headIndex));
|
||||||
|
} else {
|
||||||
|
headPos = transformPoint(myAvatar->getSensorToWorldMatrix(), myAvatar->getHMDSensorPosition());
|
||||||
|
}
|
||||||
|
hipsRot = tiltRot * hipsRot;
|
||||||
|
hipsPos = headPos + tiltRot * (hipsPos - headPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnimPose(hipsRot * Quaternions::Y_180, hipsPos);
|
||||||
|
}
|
||||||
|
|
||||||
// Called within Model::simulate call, below.
|
// Called within Model::simulate call, below.
|
||||||
void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
const FBXGeometry& geometry = getFBXGeometry();
|
const FBXGeometry& geometry = getFBXGeometry();
|
||||||
|
@ -124,6 +160,39 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if hips are not under direct control, estimate the hips position.
|
||||||
|
if (avatarHeadPose.isValid() && !params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Hips]) {
|
||||||
|
bool isFlying = (myAvatar->getCharacterController()->getState() == CharacterController::State::Hover || myAvatar->getCharacterController()->computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS);
|
||||||
|
|
||||||
|
if (!_prevHipsValid) {
|
||||||
|
AnimPose hips = computeHipsInSensorFrame(myAvatar, isFlying);
|
||||||
|
_prevHips = hips;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimPose hips = computeHipsInSensorFrame(myAvatar, isFlying);
|
||||||
|
|
||||||
|
// smootly lerp hips, in sensorframe, with different coeff for horiz and vertical translation.
|
||||||
|
const float ROT_ALPHA = 0.9f;
|
||||||
|
const float TRANS_HORIZ_ALPHA = 0.9f;
|
||||||
|
const float TRANS_VERT_ALPHA = 0.1f;
|
||||||
|
float hipsY = hips.trans().y;
|
||||||
|
hips.trans() = lerp(hips.trans(), _prevHips.trans(), TRANS_HORIZ_ALPHA);
|
||||||
|
hips.trans().y = lerp(hipsY, _prevHips.trans().y, TRANS_VERT_ALPHA);
|
||||||
|
hips.rot() = safeLerp(hips.rot(), _prevHips.rot(), ROT_ALPHA);
|
||||||
|
|
||||||
|
_prevHips = hips;
|
||||||
|
_prevHipsValid = true;
|
||||||
|
|
||||||
|
glm::mat4 invRigMat = glm::inverse(myAvatar->getTransform().getMatrix() * Matrices::Y_180);
|
||||||
|
AnimPose sensorToRigPose(invRigMat * myAvatar->getSensorToWorldMatrix());
|
||||||
|
|
||||||
|
params.primaryControllerPoses[Rig::PrimaryControllerType_Hips] = sensorToRigPose * hips;
|
||||||
|
params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Hips] = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_prevHipsValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
|
params.isTalking = head->getTimeWithoutTalking() <= 1.5f;
|
||||||
|
|
||||||
// pass detailed torso k-dops to rig.
|
// pass detailed torso k-dops to rig.
|
||||||
|
|
|
@ -25,6 +25,9 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateFingers();
|
void updateFingers();
|
||||||
|
|
||||||
|
AnimPose _prevHips; // sensor frame
|
||||||
|
bool _prevHipsValid { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_MySkeletonModel_h
|
#endif // hifi_MySkeletonModel_h
|
||||||
|
|
|
@ -16,9 +16,7 @@
|
||||||
#include "Wallet.h"
|
#include "Wallet.h"
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
|
|
||||||
HIFI_QML_DEF(QmlCommerce)
|
QmlCommerce::QmlCommerce() {
|
||||||
|
|
||||||
QmlCommerce::QmlCommerce(QQuickItem* parent) : OffscreenQmlDialog(parent) {
|
|
||||||
auto ledger = DependencyManager::get<Ledger>();
|
auto ledger = DependencyManager::get<Ledger>();
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult);
|
connect(ledger.data(), &Ledger::buyResult, this, &QmlCommerce::buyResult);
|
||||||
|
|
|
@ -16,16 +16,14 @@
|
||||||
#define hifi_QmlCommerce_h
|
#define hifi_QmlCommerce_h
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <OffscreenQmlDialog.h>
|
|
||||||
|
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
|
||||||
class QmlCommerce : public OffscreenQmlDialog {
|
class QmlCommerce : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
HIFI_QML_DECL
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QmlCommerce(QQuickItem* parent = nullptr);
|
QmlCommerce();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void walletStatusResult(uint walletStatus);
|
void walletStatusResult(uint walletStatus);
|
||||||
|
|
|
@ -23,10 +23,10 @@ static const float WEB_STYLUS_LENGTH = 0.2f;
|
||||||
static const float TABLET_MIN_HOVER_DISTANCE = -0.1f;
|
static const float TABLET_MIN_HOVER_DISTANCE = -0.1f;
|
||||||
static const float TABLET_MAX_HOVER_DISTANCE = 0.1f;
|
static const float TABLET_MAX_HOVER_DISTANCE = 0.1f;
|
||||||
static const float TABLET_MIN_TOUCH_DISTANCE = -0.1f;
|
static const float TABLET_MIN_TOUCH_DISTANCE = -0.1f;
|
||||||
static const float TABLET_MAX_TOUCH_DISTANCE = 0.01f;
|
static const float TABLET_MAX_TOUCH_DISTANCE = 0.005f;
|
||||||
|
|
||||||
static const float HOVER_HYSTERESIS = 0.01f;
|
static const float HOVER_HYSTERESIS = 0.01f;
|
||||||
static const float TOUCH_HYSTERESIS = 0.02f;
|
static const float TOUCH_HYSTERESIS = 0.001f;
|
||||||
|
|
||||||
static const float STYLUS_MOVE_DELAY = 0.33f * USECS_PER_SECOND;
|
static const float STYLUS_MOVE_DELAY = 0.33f * USECS_PER_SECOND;
|
||||||
static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f;
|
static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f;
|
||||||
|
|
|
@ -11,11 +11,12 @@
|
||||||
#include <QtCore/QLoggingCategory>
|
#include <QtCore/QLoggingCategory>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
|
#include <shared/FileUtils.h>
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
#include <Trace.h>
|
|
||||||
#include <StatTracker.h>
|
|
||||||
#include <OffscreenUi.h>
|
#include <OffscreenUi.h>
|
||||||
|
#include <StatTracker.h>
|
||||||
|
#include <Trace.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
|
@ -141,6 +142,15 @@ void TestScriptingInterface::endTraceEvent(QString name) {
|
||||||
tracing::traceEvent(trace_test(), name, tracing::DurationEnd);
|
tracing::traceEvent(trace_test(), name, tracing::DurationEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestScriptingInterface::savePhysicsSimulationStats(QString originalPath) {
|
||||||
|
QString path = FileUtils::replaceDateTimeTokens(originalPath);
|
||||||
|
path = FileUtils::computeDocumentPath(path);
|
||||||
|
if (!FileUtils::canCreateFile(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qApp->saveNextPhysicsStats(path);
|
||||||
|
}
|
||||||
|
|
||||||
void TestScriptingInterface::profileRange(const QString& name, QScriptValue fn) {
|
void TestScriptingInterface::profileRange(const QString& name, QScriptValue fn) {
|
||||||
PROFILE_RANGE(script, name);
|
PROFILE_RANGE(script, name);
|
||||||
fn.call();
|
fn.call();
|
||||||
|
|
|
@ -71,6 +71,11 @@ public slots:
|
||||||
|
|
||||||
void endTraceEvent(QString name);
|
void endTraceEvent(QString name);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Write detailed timing stats of next physics stepSimulation() to filename
|
||||||
|
*/
|
||||||
|
void savePhysicsSimulationStats(QString filename);
|
||||||
|
|
||||||
Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
|
Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
#include "scripting/HMDScriptingInterface.h"
|
#include "scripting/HMDScriptingInterface.h"
|
||||||
|
|
||||||
static const QVariant TABLET_ADDRESS_DIALOG = "TabletAddressDialog.qml";
|
static const QVariant TABLET_ADDRESS_DIALOG = "hifi/tablet/TabletAddressDialog.qml";
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void DialogsManager::maybeCreateDialog(QPointer<T>& member) {
|
void DialogsManager::maybeCreateDialog(QPointer<T>& member) {
|
||||||
if (!member) {
|
if (!member) {
|
||||||
|
@ -91,7 +91,7 @@ void DialogsManager::setDomainConnectionFailureVisibility(bool visible) {
|
||||||
ConnectionFailureDialog::hide();
|
ConnectionFailureDialog::hide();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
static const QUrl url("../../dialogs/TabletConnectionFailureDialog.qml");
|
static const QUrl url("dialogs/TabletConnectionFailureDialog.qml");
|
||||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||||
if (visible) {
|
if (visible) {
|
||||||
tablet->initialScreen(url);
|
tablet->initialScreen(url);
|
||||||
|
|
|
@ -46,7 +46,7 @@ void LoginDialog::showWithSelection()
|
||||||
if (tablet->getToolbarMode()) {
|
if (tablet->getToolbarMode()) {
|
||||||
LoginDialog::show();
|
LoginDialog::show();
|
||||||
} else {
|
} else {
|
||||||
static const QUrl url("../../dialogs/TabletLoginDialog.qml");
|
static const QUrl url("dialogs/TabletLoginDialog.qml");
|
||||||
tablet->initialScreen(url);
|
tablet->initialScreen(url);
|
||||||
if (!hmd->getShouldShowTablet()) {
|
if (!hmd->getShouldShowTablet()) {
|
||||||
hmd->openTablet();
|
hmd->openTablet();
|
||||||
|
|
|
@ -78,6 +78,8 @@ bool Stats::includeTimingRecord(const QString& name) {
|
||||||
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
||||||
} else if (name.startsWith("/paintGL/")) {
|
} else if (name.startsWith("/paintGL/")) {
|
||||||
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
||||||
|
} else if (name.startsWith("step/")) {
|
||||||
|
return Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,7 +266,7 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString INSPECTION_CERTIFICATE_QML_PATH = qApp->applicationDirPath() + "../../../qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
||||||
void ContextOverlayInterface::openInspectionCertificate() {
|
void ContextOverlayInterface::openInspectionCertificate() {
|
||||||
// lets open the tablet to the inspection certificate QML
|
// lets open the tablet to the inspection certificate QML
|
||||||
if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
|
if (!_currentEntityWithContextOverlay.isNull() && _entityMarketplaceID.length() > 0) {
|
||||||
|
|
|
@ -200,7 +200,6 @@ void Web3DOverlay::setupQmlSurface() {
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
|
_webSurface->getSurfaceContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
|
_webSurface->getSurfaceContext()->setContextProperty("MyAvatar", DependencyManager::get<AvatarManager>()->getMyAvatar().get());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("Assets", DependencyManager::get<AssetMappingsScriptingInterface>().data());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("LODManager", DependencyManager::get<LODManager>().data());
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
|
_webSurface->getSurfaceContext()->setContextProperty("OctreeStats", DependencyManager::get<OctreeStatsProvider>().data());
|
||||||
|
@ -220,9 +219,6 @@ void Web3DOverlay::setupQmlSurface() {
|
||||||
|
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
|
_webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../");
|
||||||
|
|
||||||
// Tablet inteference with Tablet.qml. Need to avoid this in QML space
|
|
||||||
_webSurface->getSurfaceContext()->setContextProperty("tabletInterface", DependencyManager::get<TabletScriptingInterface>().data());
|
|
||||||
|
|
||||||
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data());
|
tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface.data());
|
||||||
// mark the TabletProxy object as cpp ownership.
|
// mark the TabletProxy object as cpp ownership.
|
||||||
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
|
QObject* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
|
|
@ -1641,9 +1641,17 @@ void Rig::initAnimGraph(const QUrl& url) {
|
||||||
// load the anim graph
|
// load the anim graph
|
||||||
_animLoader.reset(new AnimNodeLoader(url));
|
_animLoader.reset(new AnimNodeLoader(url));
|
||||||
_animLoading = true;
|
_animLoading = true;
|
||||||
connect(_animLoader.get(), &AnimNodeLoader::success, [this](AnimNode::Pointer nodeIn) {
|
std::weak_ptr<AnimSkeleton> weakSkeletonPtr = _animSkeleton;
|
||||||
|
connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr](AnimNode::Pointer nodeIn) {
|
||||||
_animNode = nodeIn;
|
_animNode = nodeIn;
|
||||||
_animNode->setSkeleton(_animSkeleton);
|
|
||||||
|
// abort load if the previous skeleton was deleted.
|
||||||
|
auto sharedSkeletonPtr = weakSkeletonPtr.lock();
|
||||||
|
if (!sharedSkeletonPtr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_animNode->setSkeleton(sharedSkeletonPtr);
|
||||||
|
|
||||||
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
||||||
// restore the user animation we had before reset.
|
// restore the user animation we had before reset.
|
||||||
|
@ -1651,6 +1659,7 @@ void Rig::initAnimGraph(const QUrl& url) {
|
||||||
_userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
|
_userAnimState = { UserAnimState::None, "", 30.0f, false, 0.0f, 0.0f };
|
||||||
overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame);
|
overrideAnimation(origState.url, origState.fps, origState.loop, origState.firstFrame, origState.lastFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore the role animations we had before reset.
|
// restore the role animations we had before reset.
|
||||||
for (auto& roleAnimState : _roleAnimStates) {
|
for (auto& roleAnimState : _roleAnimStates) {
|
||||||
auto roleState = roleAnimState.second;
|
auto roleState = roleAnimState.second;
|
||||||
|
|
|
@ -31,7 +31,7 @@ class AnimInverseKinematics;
|
||||||
// Rig instances are reentrant.
|
// Rig instances are reentrant.
|
||||||
// However only specific methods thread-safe. Noted below.
|
// However only specific methods thread-safe. Noted below.
|
||||||
|
|
||||||
class Rig : public QObject, public std::enable_shared_from_this<Rig> {
|
class Rig : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
struct StateHandler {
|
struct StateHandler {
|
||||||
|
|
|
@ -96,9 +96,13 @@ void SoundProcessor::run() {
|
||||||
QByteArray outputAudioByteArray;
|
QByteArray outputAudioByteArray;
|
||||||
|
|
||||||
int sampleRate = interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
int sampleRate = interpretAsWav(rawAudioByteArray, outputAudioByteArray);
|
||||||
if (sampleRate != 0) {
|
if (sampleRate == 0) {
|
||||||
downSample(outputAudioByteArray, sampleRate);
|
qCDebug(audio) << "Unsupported WAV file type";
|
||||||
|
emit onError(300, "Failed to load sound file, reason: unsupported WAV file type");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downSample(outputAudioByteArray, sampleRate);
|
||||||
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
} else if (fileName.endsWith(RAW_EXTENSION)) {
|
||||||
// check if this was a stereo raw file
|
// check if this was a stereo raw file
|
||||||
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
// since it's raw the only way for us to know that is if the file was called .stereo.raw
|
||||||
|
|
|
@ -679,17 +679,13 @@ void OpenGLDisplayPlugin::internalPresent() {
|
||||||
void OpenGLDisplayPlugin::present() {
|
void OpenGLDisplayPlugin::present() {
|
||||||
auto frameId = (uint64_t)presentCount();
|
auto frameId = (uint64_t)presentCount();
|
||||||
PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, frameId)
|
PROFILE_RANGE_EX(render, __FUNCTION__, 0xffffff00, frameId)
|
||||||
|
uint64_t startPresent = usecTimestampNow();
|
||||||
{
|
{
|
||||||
PROFILE_RANGE_EX(render, "updateFrameData", 0xff00ff00, frameId)
|
PROFILE_RANGE_EX(render, "updateFrameData", 0xff00ff00, frameId)
|
||||||
updateFrameData();
|
updateFrameData();
|
||||||
}
|
}
|
||||||
incrementPresentCount();
|
incrementPresentCount();
|
||||||
|
|
||||||
{
|
|
||||||
PROFILE_RANGE_EX(render, "recycle", 0xff00ff00, frameId)
|
|
||||||
_gpuContext->recycle();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_currentFrame) {
|
if (_currentFrame) {
|
||||||
{
|
{
|
||||||
withPresentThreadLock([&] {
|
withPresentThreadLock([&] {
|
||||||
|
@ -718,6 +714,7 @@ void OpenGLDisplayPlugin::present() {
|
||||||
|
|
||||||
gpu::Backend::freeGPUMemSize.set(gpu::gl::getFreeDedicatedMemory());
|
gpu::Backend::freeGPUMemSize.set(gpu::gl::getFreeDedicatedMemory());
|
||||||
}
|
}
|
||||||
|
_movingAveragePresent.addSample((float)(usecTimestampNow() - startPresent));
|
||||||
}
|
}
|
||||||
|
|
||||||
float OpenGLDisplayPlugin::newFramePresentRate() const {
|
float OpenGLDisplayPlugin::newFramePresentRate() const {
|
||||||
|
|