Move Slider
27
BUILD_LINUX_CHEATSHEET.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# this guide is specific to Ubuntu 16.04.
|
||||||
|
# deb packages of High Fidelity domain server and assignment client are stored on debian.highfidelity.com
|
||||||
|
sudo su -
|
||||||
|
apt-get -y update
|
||||||
|
apt-get install -y software-properties-common
|
||||||
|
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 15FF1AAE
|
||||||
|
add-apt-repository "deb http://debian.highfidelity.com stable main"
|
||||||
|
apt-get -y update
|
||||||
|
apt-get install -y hifi-domain-server
|
||||||
|
apt-get install -y hifi-assignment-client
|
||||||
|
|
||||||
|
# When installing master/dev builds, the packages are slightly different and you just need to change the last 2 steps to:
|
||||||
|
apt-get install -y hifi-dev-domain-server
|
||||||
|
apt-get install -y hifi-dev-assignment-client
|
||||||
|
|
||||||
|
# domain server and assignment clients should already be running. The processes are controlled via:
|
||||||
|
systemctl start hifi-domain-server
|
||||||
|
systemctl stop hifi-domain-server
|
||||||
|
|
||||||
|
# Once the machine is setup and processes are running you should ensure that your firewall exposes port 40100 on TCP and all UDP ports. This will get your domain up and running and you could connect to it (for now) by using High Fidelity Interface and typing in the IP for the place name. (further customizations can be done via http://IPAddress:40100).
|
||||||
|
|
||||||
|
# The server always depends on both hifi-domain-server and hifi-assignment-client running at the same time.
|
||||||
|
# As an additional step, you should ensure that your packages are automatically updated when a new version goes out. You could, for example, set the automatic update checks to happen every hour (though this could potentially result in the domain being unreachable for a whole hour by new clients when they are released - adjust the update checks accordingly).
|
||||||
|
To do this you can modify /etc/crontab by adding the following lines
|
||||||
|
0 */1 * * * root apt-get update
|
||||||
|
1 */1 * * * root apt-get install --only-upgrade -y hifi-domain-server
|
||||||
|
2 */1 * * * root apt-get install --only-upgrade -y hifi-assignment-client
|
|
@ -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");
|
||||||
|
|
|
@ -214,7 +214,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
uint64_t getTimestamp() const override {
|
uint64_t getTimestamp() const override {
|
||||||
return _lastEncodeTime;
|
return _lastEncodeTime;
|
||||||
}
|
}
|
||||||
const AvatarSharedPointer& getAvatar() const { return _avatar; }
|
AvatarSharedPointer getAvatar() const { return _avatar; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AvatarSharedPointer _avatar;
|
AvatarSharedPointer _avatar;
|
||||||
|
@ -326,7 +326,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
int remainingAvatars = (int)sortedAvatars.size();
|
int remainingAvatars = (int)sortedAvatars.size();
|
||||||
while (!sortedAvatars.empty()) {
|
while (!sortedAvatars.empty()) {
|
||||||
const auto& avatarData = sortedAvatars.top().getAvatar();
|
const auto avatarData = sortedAvatars.top().getAvatar();
|
||||||
sortedAvatars.pop();
|
sortedAvatars.pop();
|
||||||
remainingAvatars--;
|
remainingAvatars--;
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
if (NOT DEV_BUILD)
|
||||||
set(INTERFACE_QML_QRC ${CMAKE_CURRENT_BINARY_DIR}/qml.qrc)
|
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)
|
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(
|
||||||
|
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,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.
|
||||||
|
@ -30,28 +29,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
|
||||||
|
|
|
@ -30,7 +30,7 @@ Original.Button {
|
||||||
|
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ Original.Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
if (action !== null) {
|
if (action !== null) {
|
||||||
action.triggered()
|
action.triggered()
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ Original.CheckBox {
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ Original.Button {
|
||||||
|
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonHover);
|
Tablet.playSound(TabletEnums.ButtonHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onActionChanged: {
|
onActionChanged: {
|
||||||
|
@ -38,7 +38,7 @@ Original.Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
if (action !== null) {
|
if (action !== null) {
|
||||||
action.triggered()
|
action.triggered()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -31,7 +31,7 @@ Original.RadioButton {
|
||||||
readonly property int checkRadius: 2
|
readonly property int checkRadius: 2
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tabletInterface.playSound(TabletEnums.ButtonClick);
|
Tablet.playSound(TabletEnums.ButtonClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
|
|
|
@ -22,28 +22,27 @@ Slider {
|
||||||
property string label: ""
|
property string label: ""
|
||||||
property real controlHeight: height + (sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0)
|
property real controlHeight: height + (sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0)
|
||||||
|
|
||||||
|
property alias minimumValue: slider.from
|
||||||
|
property alias maximumValue: slider.to
|
||||||
|
|
||||||
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control.
|
height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control.
|
||||||
y: sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0
|
y: sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0
|
||||||
|
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
|
x: slider.leftPadding
|
||||||
|
y: slider.topPadding + slider.availableHeight / 2 - height / 2
|
||||||
|
|
||||||
implicitWidth: 50
|
implicitWidth: 50
|
||||||
implicitHeight: hifi.dimensions.sliderGrooveHeight
|
implicitHeight: hifi.dimensions.sliderGrooveHeight
|
||||||
|
width: slider.availableWidth
|
||||||
|
height: implicitHeight
|
||||||
radius: height / 2
|
radius: height / 2
|
||||||
color: isLightColorScheme ? hifi.colors.sliderGutterLight : hifi.colors.sliderGutterDark
|
color: isLightColorScheme ? hifi.colors.sliderGutterLight : hifi.colors.sliderGutterDark
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: parent.height - 2
|
width: slider.visualPosition * parent.width
|
||||||
height: slider.width * (slider.value - slider.minimumValue) / (slider.maximumValue - slider.minimumValue) - 1
|
height: parent.height
|
||||||
radius: height / 2
|
radius: height / 2
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
topMargin: width + 1
|
|
||||||
left: parent.left
|
|
||||||
leftMargin: 1
|
|
||||||
}
|
|
||||||
transformOrigin: Item.TopLeft
|
|
||||||
rotation: -90
|
|
||||||
gradient: Gradient {
|
gradient: Gradient {
|
||||||
GradientStop { position: 0.0; color: hifi.colors.blueAccent }
|
GradientStop { position: 0.0; color: hifi.colors.blueAccent }
|
||||||
GradientStop { position: 1.0; color: hifi.colors.primaryHighlight }
|
GradientStop { position: 1.0; color: hifi.colors.primaryHighlight }
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -59,12 +59,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ Rectangle {
|
||||||
property string itemName;
|
property string itemName;
|
||||||
property string itemId;
|
property string itemId;
|
||||||
property string itemHref;
|
property string itemHref;
|
||||||
|
property string itemAuthor;
|
||||||
property double balanceAfterPurchase;
|
property double balanceAfterPurchase;
|
||||||
property bool alreadyOwned: false;
|
property bool alreadyOwned: false;
|
||||||
property int itemPrice: -1;
|
property int itemPrice: -1;
|
||||||
|
@ -41,10 +42,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 +61,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 +74,7 @@ Rectangle {
|
||||||
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else {
|
} else {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,12 +82,12 @@ Rectangle {
|
||||||
if (result.status !== 'success') {
|
if (result.status !== 'success') {
|
||||||
failureErrorText.text = result.message;
|
failureErrorText.text = result.message;
|
||||||
root.activeView = "checkoutFailure";
|
root.activeView = "checkoutFailure";
|
||||||
UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemPrice, !root.alreadyOwned, result.message);
|
UserActivityLogger.commercePurchaseFailure(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned, result.message);
|
||||||
} else {
|
} else {
|
||||||
root.itemHref = result.data.download_url;
|
root.itemHref = result.data.download_url;
|
||||||
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
|
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
|
||||||
root.activeView = "checkoutSuccess";
|
root.activeView = "checkoutSuccess";
|
||||||
UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemPrice, !root.alreadyOwned);
|
UserActivityLogger.commercePurchaseSuccess(root.itemId, root.itemAuthor, root.itemPrice, !root.alreadyOwned);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +117,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 +126,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 +205,7 @@ Rectangle {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
purchasesReceived = false;
|
purchasesReceived = false;
|
||||||
balanceReceived = false;
|
balanceReceived = false;
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +226,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
commerce.getLoginStatus();
|
Commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +411,8 @@ Rectangle {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: buyTextContainer;
|
id: buyTextContainer;
|
||||||
visible: buyText.text !== "";
|
visible: buyText.text !== "";
|
||||||
anchors.top: parent.top;
|
anchors.top: cancelPurchaseButton.bottom;
|
||||||
|
anchors.topMargin: 16;
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
height: buyText.height + 30;
|
height: buyText.height + 30;
|
||||||
|
@ -463,8 +467,8 @@ Rectangle {
|
||||||
enabled: (root.balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || !itemIsJson;
|
enabled: (root.balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || !itemIsJson;
|
||||||
color: hifi.buttons.blue;
|
color: hifi.buttons.blue;
|
||||||
colorScheme: hifi.colorSchemes.light;
|
colorScheme: hifi.colorSchemes.light;
|
||||||
anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top;
|
anchors.top: checkoutActionButtonsContainer.top;
|
||||||
anchors.topMargin: buyTextContainer.visible ? 12 : 16;
|
anchors.topMargin: 16;
|
||||||
height: 40;
|
height: 40;
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
|
@ -473,9 +477,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 +880,8 @@ 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;
|
||||||
|
itemAuthor = message.params.itemAuthor;
|
||||||
setBuyText();
|
setBuyText();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -923,11 +929,11 @@ Rectangle {
|
||||||
buyText.text = "";
|
buyText.text = "";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buyText.text = "This free item <b>will not</b> be added to your <b>Purchases</b>. Non-entities can't yet be purchased for HFC.";
|
buyText.text = '<i>This type of item cannot currently be certified, so it will not show up in "My Purchases". You can access it again for free from the Marketplace.</i>';
|
||||||
buyTextContainer.color = "#FFD6AD";
|
buyTextContainer.color = hifi.colors.white;
|
||||||
buyTextContainer.border.color = "#FAC07D";
|
buyTextContainer.border.color = hifi.colors.white;
|
||||||
buyGlyph.text = hifi.glyphs.alert;
|
buyGlyph.text = "";
|
||||||
buyGlyph.size = 46;
|
buyGlyph.size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,8 +945,8 @@ Rectangle {
|
||||||
}
|
}
|
||||||
root.balanceReceived = false;
|
root.balanceReceived = false;
|
||||||
root.purchasesReceived = false;
|
root.purchasesReceived = false;
|
||||||
commerce.inventory();
|
Commerce.inventory();
|
||||||
commerce.balance();
|
Commerce.balance();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -30,14 +30,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);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ Item {
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
sendToParent({method: "needsLogIn"});
|
sendToParent({method: "needsLogIn"});
|
||||||
} else {
|
} else {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,13 +60,13 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
commerce.getLoginStatus();
|
Commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,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') {
|
||||||
|
@ -108,7 +108,7 @@ Rectangle {
|
||||||
|
|
||||||
onCertificateIdChanged: {
|
onCertificateIdChanged: {
|
||||||
if (certificateId !== "") {
|
if (certificateId !== "") {
|
||||||
commerce.certificateInfo(certificateId);
|
Commerce.certificateInfo(certificateId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,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) {
|
||||||
|
@ -53,13 +53,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);
|
||||||
|
@ -70,7 +71,7 @@ Rectangle {
|
||||||
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
if (!isLoggedIn && root.activeView !== "needsLogIn") {
|
||||||
root.activeView = "needsLogIn";
|
root.activeView = "needsLogIn";
|
||||||
} else {
|
} else {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +197,7 @@ Rectangle {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
securityImageResultReceived = false;
|
securityImageResultReceived = false;
|
||||||
purchasesReceived = false;
|
purchasesReceived = false;
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +218,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
commerce.getLoginStatus();
|
Commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +233,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);
|
||||||
}
|
}
|
||||||
|
@ -253,7 +254,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,7 +594,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;
|
||||||
|
|
|
@ -29,8 +29,8 @@ Item {
|
||||||
source: "images/wallet-bg.jpg";
|
source: "images/wallet-bg.jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -24,10 +24,6 @@ Item {
|
||||||
|
|
||||||
id: root;
|
id: root;
|
||||||
|
|
||||||
SecurityImageModel {
|
|
||||||
id: securityImageModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Username Text
|
// Username Text
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
id: usernameText;
|
id: usernameText;
|
||||||
|
|
|
@ -35,8 +35,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 = "";
|
||||||
|
@ -49,8 +49,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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +73,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 {
|
||||||
|
@ -207,7 +212,7 @@ Item {
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
submitPassphraseInputButton.enabled = false;
|
submitPassphraseInputButton.enabled = false;
|
||||||
commerce.setPassphrase(passphraseField.text);
|
Commerce.setPassphrase(passphraseField.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +252,7 @@ Item {
|
||||||
source: "image://security/securityImage";
|
source: "image://security/securityImage";
|
||||||
cache: false;
|
cache: false;
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
commerce.getSecurityImage();
|
Commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
|
@ -315,7 +320,7 @@ Item {
|
||||||
text: "Submit"
|
text: "Submit"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
submitPassphraseInputButton.enabled = false;
|
submitPassphraseInputButton.enabled = false;
|
||||||
commerce.setPassphrase(passphraseField.text);
|
Commerce.setPassphrase(passphraseField.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,6 +340,7 @@ Item {
|
||||||
text: "Cancel"
|
text: "Cancel"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
sendSignalToParent({method: 'passphrasePopup_cancelClicked'});
|
sendSignalToParent({method: 'passphrasePopup_cancelClicked'});
|
||||||
|
UserActivityLogger.commercePassphraseAuthenticationStatus("passphrase modal cancelled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,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";
|
||||||
|
@ -53,6 +53,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();
|
||||||
}
|
}
|
||||||
|
@ -159,7 +162,7 @@ Item {
|
||||||
source: "image://security/securityImage";
|
source: "image://security/securityImage";
|
||||||
cache: false;
|
cache: false;
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
commerce.getSecurityImage();
|
Commerce.getSecurityImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
|
@ -282,7 +285,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,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;
|
||||||
|
@ -233,7 +233,7 @@ Item {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getKeyFilePathIfExists();
|
Commerce.getKeyFilePathIfExists();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,12 +25,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 = "";
|
||||||
|
@ -212,4 +208,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;
|
||||||
}
|
}
|
||||||
ListElement{
|
array[array.length] = randomNumber;
|
||||||
sourcePath: "images/02.jpg"
|
|
||||||
securityImageEnumValue: 2;
|
|
||||||
}
|
}
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/03.jpg"
|
var modelElement;
|
||||||
securityImageEnumValue: 3;
|
|
||||||
|
for (var i = 0; i < 6; i++) {
|
||||||
|
modelElement = { "sourcePath":"images/" + addLeadingZero(array[i]) + ".jpg", "securityImageEnumValue": (i + 1) }
|
||||||
|
root.insert(i, modelElement);
|
||||||
}
|
}
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/04.jpg"
|
|
||||||
securityImageEnumValue: 4;
|
|
||||||
}
|
}
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/05.jpg"
|
function addLeadingZero(n) {
|
||||||
securityImageEnumValue: 5;
|
return n < 10 ? '0' + n : '' + n;
|
||||||
}
|
|
||||||
ListElement{
|
|
||||||
sourcePath: "images/06.jpg"
|
|
||||||
securityImageEnumValue: 6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getImagePathFromImageID(imageID) {
|
function getImagePathFromImageID(imageID) {
|
||||||
|
|
|
@ -94,6 +94,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
|
||||||
//
|
//
|
||||||
|
|
|
@ -24,8 +24,8 @@ Item {
|
||||||
|
|
||||||
id: root;
|
id: root;
|
||||||
|
|
||||||
Hifi.QmlCommerce {
|
Connections {
|
||||||
id: commerce;
|
target: Commerce;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Unavailable"
|
// "Unavailable"
|
||||||
|
|
|
@ -30,13 +30,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) {
|
||||||
|
@ -46,7 +48,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();
|
||||||
|
@ -56,10 +58,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) {
|
||||||
|
if (root.activeView !== "walletSetup") {
|
||||||
root.activeView = "walletHome";
|
root.activeView = "walletHome";
|
||||||
commerce.getSecurityImage();
|
Commerce.getSecurityImage();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus);
|
console.log("ERROR in Wallet.qml: Unknown wallet status: " + walletStatus);
|
||||||
}
|
}
|
||||||
|
@ -69,7 +74,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,10 +86,6 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SecurityImageModel {
|
|
||||||
id: securityImageModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiCommerceCommon.CommerceLightbox {
|
HifiCommerceCommon.CommerceLightbox {
|
||||||
id: lightboxPopup;
|
id: lightboxPopup;
|
||||||
visible: false;
|
visible: false;
|
||||||
|
@ -179,7 +180,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 {
|
||||||
|
@ -208,6 +209,7 @@ Rectangle {
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
onSendSignalToWallet: {
|
onSendSignalToWallet: {
|
||||||
|
if (passphraseChange.visible) {
|
||||||
if (msg.method === 'walletSetup_raiseKeyboard') {
|
if (msg.method === 'walletSetup_raiseKeyboard') {
|
||||||
root.keyboardRaised = true;
|
root.keyboardRaised = true;
|
||||||
root.isPassword = msg.isPasswordField;
|
root.isPassword = msg.isPasswordField;
|
||||||
|
@ -223,6 +225,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
SecurityImageChange {
|
SecurityImageChange {
|
||||||
id: securityImageChange;
|
id: securityImageChange;
|
||||||
visible: root.activeView === "securityImageChange";
|
visible: root.activeView === "securityImageChange";
|
||||||
|
@ -259,7 +262,7 @@ Rectangle {
|
||||||
color: hifi.colors.baseGray;
|
color: hifi.colors.baseGray;
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +283,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
target: GlobalServices
|
target: GlobalServices
|
||||||
onMyUsernameChanged: {
|
onMyUsernameChanged: {
|
||||||
commerce.getLoginStatus();
|
Commerce.getLoginStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +297,7 @@ Rectangle {
|
||||||
Connections {
|
Connections {
|
||||||
onSendSignalToParent: {
|
onSendSignalToParent: {
|
||||||
if (msg.method === "authSuccess") {
|
if (msg.method === "authSuccess") {
|
||||||
commerce.getWalletStatus();
|
Commerce.getWalletStatus();
|
||||||
} else {
|
} else {
|
||||||
sendToScript(msg);
|
sendToScript(msg);
|
||||||
}
|
}
|
||||||
|
@ -341,6 +344,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,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") {
|
||||||
|
@ -235,6 +235,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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +251,7 @@ Item {
|
||||||
height: 50;
|
height: 50;
|
||||||
text: "Cancel";
|
text: "Cancel";
|
||||||
onClicked: {
|
onClicked: {
|
||||||
sendSignalToWallet({method: 'walletSetup_cancelClicked'});
|
sendSignalToWallet({method: 'walletSetup_cancelClicked', referrer: root.referrer });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -364,7 +365,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();
|
||||||
}
|
}
|
||||||
|
@ -447,7 +448,7 @@ Item {
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
commerce.getWalletAuthenticatedStatus();
|
Commerce.getWalletAuthenticatedStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,7 +534,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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -666,7 +667,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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,12 +75,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,37 +67,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;
|
||||||
|
loader.item.url = url;
|
||||||
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
||||||
loader.item.gotoPreviousApp = true;
|
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() {
|
||||||
|
@ -109,7 +108,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,14 +171,6 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: loader
|
|
||||||
objectName: "loader"
|
|
||||||
asynchronous: false
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
// Hook up callback for clara.io download from the marketplace.
|
// Hook up callback for clara.io download from the marketplace.
|
||||||
Connections {
|
Connections {
|
||||||
id: eventBridgeConnection
|
id: eventBridgeConnection
|
||||||
|
@ -191,7 +182,42 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
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")) {
|
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||||
}
|
}
|
||||||
|
@ -210,6 +236,11 @@ Item {
|
||||||
openBrowser.destroy();
|
openBrowser.destroy();
|
||||||
openBrowser = null;
|
openBrowser = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
|
||||||
|
|
||||||
function loadTabletWebBase() {
|
|
||||||
loader.source = "";
|
|
||||||
loader.source = "./BlocksWebView.qml";
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadWebUrl(url, injectedJavaScriptUrl) {
|
|
||||||
loader.item.url = url;
|
loader.item.url = url;
|
||||||
loader.item.scriptURL = injectedJavaScriptUrl;
|
|
||||||
if (loader.item.hasOwnProperty("closeButtonVisible")) {
|
if (loader.item.hasOwnProperty("closeButtonVisible")) {
|
||||||
loader.item.closeButtonVisible = false;
|
loader.item.closeButtonVisible = false;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadWebBase(url, injectJavaScriptUrl) {
|
||||||
|
loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadTabletWebBase(url, injectJavaScriptUrl) {
|
||||||
|
loadWebContent("hifi/tablet/BlocksWebView.qml", url, injectJavaScriptUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// used to send a message from qml to interface script.
|
// used to send a message from qml to interface script.
|
||||||
|
@ -111,16 +110,6 @@ Windows.ScrollingWindow {
|
||||||
username = newUsername;
|
username = newUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: loader
|
|
||||||
objectName: "loader"
|
|
||||||
asynchronous: false
|
|
||||||
|
|
||||||
height: pane.scrollHeight
|
|
||||||
width: pane.contentWidth
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
|
|
||||||
// Hook up callback for clara.io download from the marketplace.
|
// Hook up callback for clara.io download from the marketplace.
|
||||||
Connections {
|
Connections {
|
||||||
id: eventBridgeConnection
|
id: eventBridgeConnection
|
||||||
|
@ -132,7 +121,41 @@ Windows.ScrollingWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
Item {
|
||||||
|
id: loader
|
||||||
|
objectName: "loader";
|
||||||
|
property string source: "";
|
||||||
|
property var item: null;
|
||||||
|
|
||||||
|
height: pane.scrollHeight
|
||||||
|
width: pane.contentWidth
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
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.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")) {
|
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||||
}
|
}
|
||||||
|
@ -140,9 +163,15 @@ Windows.ScrollingWindow {
|
||||||
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
loader.item.setRootMenu(tabletRoot.rootMenu, tabletRoot.subMenu);
|
||||||
}
|
}
|
||||||
loader.item.forceActiveFocus();
|
loader.item.forceActiveFocus();
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
implicitWidth: 480
|
implicitWidth: 480
|
||||||
implicitHeight: 706
|
implicitHeight: 706
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,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
|
||||||
|
@ -22,8 +24,6 @@ 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
|
||||||
|
@ -31,15 +31,25 @@ Window {
|
||||||
property alias y: window.y
|
property alias y: window.y
|
||||||
}
|
}
|
||||||
|
|
||||||
onHorizontalChanged: {
|
Component {
|
||||||
var newParent = horizontal ? row : column;
|
id: buttonComponent
|
||||||
for (var i in buttons) {
|
ToolbarButton {
|
||||||
var child = buttons[i];
|
id: toolbarButton
|
||||||
child.parent = newParent;
|
property var proxy: modelData;
|
||||||
if (horizontal) {
|
onClicked: proxy.clicked()
|
||||||
child.y = 0
|
Component.onCompleted: updateProperties()
|
||||||
} else {
|
|
||||||
child.x = 0
|
Connections {
|
||||||
|
target: proxy;
|
||||||
|
onPropertiesChanged: updateProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateProperties() {
|
||||||
|
Object.keys(proxy.properties).forEach(function (key) {
|
||||||
|
if (toolbarButton[key] !== proxy.properties[key]) {
|
||||||
|
toolbarButton[key] = proxy.properties[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,97 +61,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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,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());
|
||||||
|
@ -4280,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();
|
||||||
}
|
}
|
||||||
|
@ -5828,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);
|
||||||
|
@ -7237,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);
|
||||||
|
bool wasRepositionLocked = false;
|
||||||
|
if (desktop) {
|
||||||
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
|
// Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below.
|
||||||
bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
|
wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool();
|
||||||
offscreenUi->getDesktop()->setProperty("repositionLocked", true);
|
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);
|
||||||
|
@ -7289,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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
if (elapsedSinceUpShift > UP_SHIFT_ELPASED) {
|
} else if (currentFPS > getLODIncreaseFPS()) {
|
||||||
|
if (now > _increaseFPSExpiry) {
|
||||||
if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) {
|
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
|
|
||||||
// Octee items... stepwise adjustment
|
|
||||||
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
|
if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
|
||||||
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;
|
||||||
} else {
|
} else {
|
||||||
_octreeSizeScale *= ADJUST_LOD_UP_BY;
|
_octreeSizeScale *= LOD_AUTO_ADJUST_INCREMENT_FACTOR;
|
||||||
}
|
}
|
||||||
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
|
if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
|
||||||
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
|
_octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE;
|
||||||
}
|
}
|
||||||
changed = true;
|
qCDebug(interfaceapp) << "adjusting LOD UP"
|
||||||
}
|
<< "fps =" << currentFPS
|
||||||
}
|
<< "targetFPS =" << getLODDecreaseFPS()
|
||||||
|
<< "octreeSizeScale =" << _octreeSizeScale;
|
||||||
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();
|
emit LODIncreased();
|
||||||
}
|
}
|
||||||
|
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
}
|
}
|
||||||
|
_decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
|
} else {
|
||||||
|
_increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD;
|
||||||
|
_decreaseFPSExpiry = _increaseFPSExpiry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (oldOctreeSizeScale != _octreeSizeScale) {
|
||||||
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
|
auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog();
|
||||||
if (lodToolsDialog) {
|
if (lodToolsDialog) {
|
||||||
lodToolsDialog->reloadSliders();
|
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();
|
||||||
|
|
|
@ -150,7 +150,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
|
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
|
||||||
float getRadius() const override { return std::static_pointer_cast<Avatar>(_avatar)->getBoundingRadius(); }
|
float getRadius() const override { return std::static_pointer_cast<Avatar>(_avatar)->getBoundingRadius(); }
|
||||||
uint64_t getTimestamp() const override { return std::static_pointer_cast<Avatar>(_avatar)->getLastRenderUpdateTime(); }
|
uint64_t getTimestamp() const override { return std::static_pointer_cast<Avatar>(_avatar)->getLastRenderUpdateTime(); }
|
||||||
const AvatarSharedPointer& getAvatar() const { return _avatar; }
|
AvatarSharedPointer getAvatar() const { return _avatar; }
|
||||||
private:
|
private:
|
||||||
AvatarSharedPointer _avatar;
|
AvatarSharedPointer _avatar;
|
||||||
};
|
};
|
||||||
|
@ -185,7 +185,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
render::Transaction transaction;
|
render::Transaction transaction;
|
||||||
while (!sortedAvatars.empty()) {
|
while (!sortedAvatars.empty()) {
|
||||||
const SortableAvatar& sortData = sortedAvatars.top();
|
const SortableAvatar& sortData = sortedAvatars.top();
|
||||||
const auto& avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar());
|
const auto avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar());
|
||||||
|
|
||||||
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
|
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
|
||||||
if (ignoring) {
|
if (ignoring) {
|
||||||
|
@ -239,7 +239,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||||
sortedAvatars.pop();
|
sortedAvatars.pop();
|
||||||
while (inView && !sortedAvatars.empty()) {
|
while (inView && !sortedAvatars.empty()) {
|
||||||
const SortableAvatar& newSortData = sortedAvatars.top();
|
const SortableAvatar& newSortData = sortedAvatars.top();
|
||||||
const auto& newAvatar = std::static_pointer_cast<Avatar>(newSortData.getAvatar());
|
const auto newAvatar = std::static_pointer_cast<Avatar>(newSortData.getAvatar());
|
||||||
inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
inView = newSortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
||||||
if (inView && newAvatar->hasNewJointData()) {
|
if (inView && newAvatar->hasNewJointData()) {
|
||||||
numAVatarsNotUpdated++;
|
numAVatarsNotUpdated++;
|
||||||
|
|
|
@ -61,7 +61,7 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString
|
||||||
|
|
||||||
void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) {
|
void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) {
|
||||||
auto wallet = DependencyManager::get<Wallet>();
|
auto wallet = DependencyManager::get<Wallet>();
|
||||||
QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key);
|
QString signature = wallet->signWithKey(text, key);
|
||||||
QJsonObject request;
|
QJsonObject request;
|
||||||
request[propertyName] = QString(text);
|
request[propertyName] = QString(text);
|
||||||
if (!controlled_failure) {
|
if (!controlled_failure) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -548,13 +548,16 @@ QStringList Wallet::listPublicKeys() {
|
||||||
// the horror of code pages and so on (changing the bytes) by just returning a base64
|
// the horror of code pages and so on (changing the bytes) by just returning a base64
|
||||||
// encoded string representing the signature (suitable for http, etc...)
|
// encoded string representing the signature (suitable for http, etc...)
|
||||||
QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
|
QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
|
||||||
qCInfo(commerce) << "Signing text" << text << "with key" << key;
|
|
||||||
EC_KEY* ecPrivateKey = NULL;
|
EC_KEY* ecPrivateKey = NULL;
|
||||||
|
|
||||||
|
auto keyFilePathString = keyFilePath().toStdString();
|
||||||
if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
|
if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
|
||||||
unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)];
|
unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)];
|
||||||
|
|
||||||
unsigned int signatureBytes = 0;
|
unsigned int signatureBytes = 0;
|
||||||
|
|
||||||
|
qCInfo(commerce) << "Hashing and signing plaintext" << text << "with key at address" << ecPrivateKey;
|
||||||
|
|
||||||
QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256);
|
QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256);
|
||||||
|
|
||||||
|
|
||||||
|
@ -747,12 +750,10 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
|
||||||
}
|
}
|
||||||
|
|
||||||
EC_KEY_free(ec);
|
EC_KEY_free(ec);
|
||||||
QByteArray ba = sig.toLocal8Bit();
|
|
||||||
const char *sigChar = ba.data();
|
|
||||||
|
|
||||||
QByteArray textByteArray;
|
QByteArray textByteArray;
|
||||||
if (status > -1) {
|
if (status > -1) {
|
||||||
textByteArray = QByteArray(sigChar, (int) strlen(sigChar));
|
textByteArray = sig.toUtf8();
|
||||||
}
|
}
|
||||||
textByteArraySize = textByteArray.size();
|
textByteArraySize = textByteArray.size();
|
||||||
int certIDSize = certID.size();
|
int certIDSize = certID.size();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -24,7 +24,6 @@ ModelOverlay::ModelOverlay()
|
||||||
: _model(std::make_shared<Model>(nullptr, this)),
|
: _model(std::make_shared<Model>(nullptr, this)),
|
||||||
_modelTextures(QVariantMap())
|
_modelTextures(QVariantMap())
|
||||||
{
|
{
|
||||||
_model->init();
|
|
||||||
_model->setLoadingPriority(_loadPriority);
|
_model->setLoadingPriority(_loadPriority);
|
||||||
_isLoaded = false;
|
_isLoaded = false;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +37,6 @@ ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) :
|
||||||
_scaleToFit(modelOverlay->_scaleToFit),
|
_scaleToFit(modelOverlay->_scaleToFit),
|
||||||
_loadPriority(modelOverlay->_loadPriority)
|
_loadPriority(modelOverlay->_loadPriority)
|
||||||
{
|
{
|
||||||
_model->init();
|
|
||||||
_model->setLoadingPriority(_loadPriority);
|
_model->setLoadingPriority(_loadPriority);
|
||||||
if (_url.isValid()) {
|
if (_url.isValid()) {
|
||||||
_updateModel = true;
|
_updateModel = true;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -138,7 +138,6 @@ Avatar::~Avatar() {
|
||||||
|
|
||||||
void Avatar::init() {
|
void Avatar::init() {
|
||||||
getHead()->init();
|
getHead()->init();
|
||||||
_skeletonModel->init();
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -349,7 +349,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
|
||||||
float getRadius() const override { return 0.5f * _renderer->getEntity()->getQueryAACube().getScale(); }
|
float getRadius() const override { return 0.5f * _renderer->getEntity()->getQueryAACube().getScale(); }
|
||||||
uint64_t getTimestamp() const override { return _renderer->getUpdateTime(); }
|
uint64_t getTimestamp() const override { return _renderer->getUpdateTime(); }
|
||||||
|
|
||||||
const EntityRendererPointer& getRenderer() const { return _renderer; }
|
EntityRendererPointer getRenderer() const { return _renderer; }
|
||||||
private:
|
private:
|
||||||
EntityRendererPointer _renderer;
|
EntityRendererPointer _renderer;
|
||||||
};
|
};
|
||||||
|
@ -382,7 +382,7 @@ void EntityTreeRenderer::updateChangedEntities(const render::ScenePointer& scene
|
||||||
std::unordered_map<EntityItemID, EntityRendererPointer>::iterator itr;
|
std::unordered_map<EntityItemID, EntityRendererPointer>::iterator itr;
|
||||||
size_t numSorted = sortedRenderables.size();
|
size_t numSorted = sortedRenderables.size();
|
||||||
while (!sortedRenderables.empty() && usecTimestampNow() < expiry) {
|
while (!sortedRenderables.empty() && usecTimestampNow() < expiry) {
|
||||||
const EntityRendererPointer& renderable = sortedRenderables.top().getRenderer();
|
const auto renderable = sortedRenderables.top().getRenderer();
|
||||||
renderable->updateInScene(scene, transaction);
|
renderable->updateInScene(scene, transaction);
|
||||||
_renderablesToUpdate.erase(renderable->getEntity()->getID());
|
_renderablesToUpdate.erase(renderable->getEntity()->getID());
|
||||||
sortedRenderables.pop();
|
sortedRenderables.pop();
|
||||||
|
|
|
@ -993,19 +993,15 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// the current frame is set on the server in update() in ModelEntityItem.cpp
|
float currentFrame = fmod(entity->getAnimationCurrentFrame(), (float)(frameCount));
|
||||||
int animationCurrentFrame = (int)(glm::floor(entity->getAnimationCurrentFrame()));
|
if (currentFrame < 0.0f) {
|
||||||
|
currentFrame += (float)frameCount;
|
||||||
// in the case where the last frame is greater than the framecount then clamp
|
|
||||||
// it to the end of the animation until it loops around.
|
|
||||||
if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) {
|
|
||||||
animationCurrentFrame = 0;
|
|
||||||
}
|
}
|
||||||
|
int currentIntegerFrame = (int)(glm::floor(currentFrame));
|
||||||
if (animationCurrentFrame == _lastKnownCurrentFrame) {
|
if (currentIntegerFrame == _lastKnownCurrentFrame) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_lastKnownCurrentFrame = animationCurrentFrame;
|
_lastKnownCurrentFrame = currentIntegerFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_jointMapping.size() != _model->getJointStateCount()) {
|
if (_jointMapping.size() != _model->getJointStateCount()) {
|
||||||
|
@ -1213,7 +1209,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
|
||||||
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
|
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
|
||||||
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
|
||||||
model->init();
|
|
||||||
entity->setModel(model);
|
entity->setModel(model);
|
||||||
withWriteLock([&] { _model = model; });
|
withWriteLock([&] { _model = model; });
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,6 +303,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) {
|
||||||
batch.setInputBuffer(0, _verticesBuffer, 0, sizeof(Vertex));
|
batch.setInputBuffer(0, _verticesBuffer, 0, sizeof(Vertex));
|
||||||
|
|
||||||
#ifndef POLYLINE_ENTITY_USE_FADE_EFFECT
|
#ifndef POLYLINE_ENTITY_USE_FADE_EFFECT
|
||||||
|
// glColor4f must be called after setInputFormat if it must be taken into account
|
||||||
if (_isFading) {
|
if (_isFading) {
|
||||||
batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime));
|
batch._glColor4f(1.0f, 1.0f, 1.0f, Interpolate::calculateFadeRatio(_fadeStartTime));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -137,11 +137,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (proceduralRender) {
|
if (proceduralRender) {
|
||||||
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
|
|
||||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
|
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
|
||||||
geometryCache->renderWireShape(batch, geometryShape);
|
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
||||||
} else {
|
} else {
|
||||||
geometryCache->renderShape(batch, geometryShape);
|
geometryCache->renderShape(batch, geometryShape, outColor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
// FIXME, support instanced multi-shape rendering using multidraw indirect
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
using namespace render;
|
using namespace render;
|
||||||
using namespace render::entities;
|
using namespace render::entities;
|
||||||
|
|
||||||
|
static const QString WEB_ENTITY_QML = "controls/WebEntityView.qml";
|
||||||
|
|
||||||
const float METERS_TO_INCHES = 39.3701f;
|
const float METERS_TO_INCHES = 39.3701f;
|
||||||
static uint32_t _currentWebCount{ 0 };
|
static uint32_t _currentWebCount{ 0 };
|
||||||
// Don't allow more than 100 concurrent web views
|
// Don't allow more than 100 concurrent web views
|
||||||
|
@ -124,7 +126,10 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
// This work must be done on the main thread
|
// This work must be done on the main thread
|
||||||
if (!hasWebSurface()) {
|
if (!hasWebSurface()) {
|
||||||
buildWebSurface(entity);
|
// If we couldn't create a new web surface, exit
|
||||||
|
if (!buildWebSurface(entity)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_contextPosition != entity->getWorldPosition()) {
|
if (_contextPosition != entity->getWorldPosition()) {
|
||||||
|
@ -188,7 +193,6 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
|
||||||
});
|
});
|
||||||
batch.setResourceTexture(0, _texture);
|
batch.setResourceTexture(0, _texture);
|
||||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||||
batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio);
|
|
||||||
|
|
||||||
DependencyManager::get<GeometryCache>()->bindWebBrowserProgram(batch, fadeRatio < OPAQUE_ALPHA_THRESHOLD);
|
DependencyManager::get<GeometryCache>()->bindWebBrowserProgram(batch, fadeRatio < OPAQUE_ALPHA_THRESHOLD);
|
||||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio), _geometryId);
|
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio), _geometryId);
|
||||||
|
@ -218,6 +222,7 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) {
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
|
// FIXME use the surface cache instead of explicit creation
|
||||||
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
|
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
|
||||||
_webSurface->create();
|
_webSurface->create();
|
||||||
}
|
}
|
||||||
|
@ -291,7 +296,6 @@ void WebEntityRenderer::loadSourceURL() {
|
||||||
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
|
if (sourceUrl.scheme() == "http" || sourceUrl.scheme() == "https" ||
|
||||||
_lastSourceUrl.toLower().endsWith(".htm") || _lastSourceUrl.toLower().endsWith(".html")) {
|
_lastSourceUrl.toLower().endsWith(".htm") || _lastSourceUrl.toLower().endsWith(".html")) {
|
||||||
_contentType = htmlContent;
|
_contentType = htmlContent;
|
||||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "qml/controls/"));
|
|
||||||
|
|
||||||
// We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS.
|
// We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS.
|
||||||
if (sourceUrl.host().endsWith("youtube.com", Qt::CaseInsensitive)) {
|
if (sourceUrl.host().endsWith("youtube.com", Qt::CaseInsensitive)) {
|
||||||
|
@ -300,12 +304,11 @@ void WebEntityRenderer::loadSourceURL() {
|
||||||
_webSurface->setMaxFps(DEFAULT_MAX_FPS);
|
_webSurface->setMaxFps(DEFAULT_MAX_FPS);
|
||||||
}
|
}
|
||||||
|
|
||||||
_webSurface->load("WebEntityView.qml", [this](QQmlContext* context, QObject* item) {
|
_webSurface->load("controls/WebEntityView.qml", [this](QQmlContext* context, QObject* item) {
|
||||||
item->setProperty("url", _lastSourceUrl);
|
item->setProperty("url", _lastSourceUrl);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_contentType = qmlContent;
|
_contentType = qmlContent;
|
||||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath()));
|
|
||||||
_webSurface->load(_lastSourceUrl);
|
_webSurface->load(_lastSourceUrl);
|
||||||
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
|
if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") {
|
||||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||||
|
|