Merge remote-tracking branch 'upstream/master' into feature/quest

This commit is contained in:
Brad Davis 2019-02-06 10:15:36 -08:00
commit 91e18f569b
42 changed files with 1000 additions and 334 deletions

View file

@ -112,7 +112,6 @@ void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer<Rec
if (_entityViewer.getTree() && !_shuttingDown) {
qCDebug(entity_script_server) << "Reloading: " << entityID;
_entitiesScriptEngine->unloadEntityScript(entityID);
checkAndCallPreload(entityID, true);
}
}
@ -184,7 +183,6 @@ void EntityScriptServer::updateEntityPPS() {
pps = std::min(_maxEntityPPS, pps);
}
_entityEditSender.setPacketsPerSecond(pps);
qDebug() << QString("Updating entity PPS to: %1 @ %2 PPS per script = %3 PPS").arg(numRunningScripts).arg(_entityPPSPerScript).arg(pps);
}
void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
@ -525,23 +523,25 @@ void EntityScriptServer::deletingEntity(const EntityItemID& entityID) {
void EntityScriptServer::entityServerScriptChanging(const EntityItemID& entityID, bool reload) {
if (_entityViewer.getTree() && !_shuttingDown) {
_entitiesScriptEngine->unloadEntityScript(entityID, true);
checkAndCallPreload(entityID, reload);
}
}
void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool reload) {
void EntityScriptServer::checkAndCallPreload(const EntityItemID& entityID, bool forceRedownload) {
if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) {
EntityItemPointer entity = _entityViewer.getTree()->findEntityByEntityItemID(entityID);
EntityScriptDetails details;
bool notRunning = !_entitiesScriptEngine->getEntityScriptDetails(entityID, details);
if (entity && (reload || notRunning || details.scriptText != entity->getServerScripts())) {
bool isRunning = _entitiesScriptEngine->getEntityScriptDetails(entityID, details);
if (entity && (forceRedownload || !isRunning || details.scriptText != entity->getServerScripts())) {
if (isRunning) {
_entitiesScriptEngine->unloadEntityScript(entityID, true);
}
QString scriptUrl = entity->getServerScripts();
if (!scriptUrl.isEmpty()) {
scriptUrl = DependencyManager::get<ResourceManager>()->normalizeURL(scriptUrl);
qCDebug(entity_script_server) << "Loading entity server script" << scriptUrl << "for" << entityID;
_entitiesScriptEngine->loadEntityScript(entityID, scriptUrl, reload);
_entitiesScriptEngine->loadEntityScript(entityID, scriptUrl, forceRedownload);
}
}
}

View file

@ -67,7 +67,7 @@ private:
void addingEntity(const EntityItemID& entityID);
void deletingEntity(const EntityItemID& entityID);
void entityServerScriptChanging(const EntityItemID& entityID, bool reload);
void checkAndCallPreload(const EntityItemID& entityID, bool reload = false);
void checkAndCallPreload(const EntityItemID& entityID, bool forceRedownload = false);
void cleanupOldKilledListeners();

View file

@ -0,0 +1,275 @@
import QtQuick 2.5
import QtWebChannel 1.0
import QtWebEngine 1.5
import controlsUit 1.0
import stylesUit 1.0
import "qrc:////qml//windows"
ScrollingWindow {
id: root
HifiConstants { id: hifi }
//HifiStyles.HifiConstants { id: hifistyles }
title: "Browser"
resizable: true
destroyOnHidden: true
width: 800
height: 600
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
property alias url: webview.url
property alias webView: webview
signal loadingChanged(int status)
x: 100
y: 100
Component.onCompleted: {
focus = true
shown = true
addressBar.text = webview.url
}
function setProfile(profile) {
webview.profile = profile;
}
function showPermissionsBar(){
permissionsContainer.visible=true;
}
function hidePermissionsBar(){
permissionsContainer.visible=false;
}
function allowPermissions(){
webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true);
hidePermissionsBar();
}
function setAutoAdd(auto) {
desktop.setAutoAdd(auto);
}
Item {
id:item
width: pane.contentWidth
implicitHeight: pane.scrollHeight
Row {
id: buttons
spacing: 4
anchors.top: parent.top
anchors.topMargin: 8
anchors.left: parent.left
anchors.leftMargin: 8
HiFiGlyphs {
id: back;
enabled: webview.canGoBack;
text: hifi.glyphs.backward
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goBack() }
}
HiFiGlyphs {
id: forward;
enabled: webview.canGoForward;
text: hifi.glyphs.forward
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
HiFiGlyphs {
id: reload;
enabled: webview.canGoForward;
text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
}
Item {
id: border
height: 48
anchors.top: parent.top
anchors.topMargin: 8
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: buttons.right
anchors.leftMargin: 8
Item {
id: barIcon
width: parent.height
height: parent.height
Image {
source: webview.icon;
x: (parent.height - height) / 2
y: (parent.width - width) / 2
sourceSize: Qt.size(width, height);
verticalAlignment: Image.AlignVCenter;
horizontalAlignment: Image.AlignHCenter
}
}
TextField {
id: addressBar
anchors.right: parent.right
anchors.rightMargin: 8
anchors.left: barIcon.right
anchors.leftMargin: 0
anchors.verticalCenter: parent.verticalCenter
focus: true
colorScheme: hifi.colorSchemes.dark
placeholderText: "Enter URL"
Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i")
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
event.accepted = true
if (text.indexOf("http") != 0) {
text = "http://" + text;
}
root.hidePermissionsBar();
root.keyboardRaised = false;
webview.url = text;
break;
}
}
}
}
Rectangle {
id:permissionsContainer
visible:false
color: "#000000"
width: parent.width
anchors.top: buttons.bottom
height:40
z:100
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
GradientStop { position: 1.0; color: "grey" }
}
RalewayLight {
id: permissionsInfo
anchors.right:permissionsRow.left
anchors.rightMargin: 32
anchors.topMargin:8
anchors.top:parent.top
text: "This site wants to use your microphone/camera"
size: 18
color: hifi.colors.white
}
Row {
id: permissionsRow
spacing: 4
anchors.top:parent.top
anchors.topMargin: 8
anchors.right: parent.right
visible: true
z:101
Button {
id:allow
text: "Allow"
color: hifi.buttons.blue
colorScheme: root.colorScheme
width: 120
enabled: true
onClicked: root.allowPermissions();
z:101
}
Button {
id:block
text: "Block"
color: hifi.buttons.red
colorScheme: root.colorScheme
width: 120
enabled: true
onClicked: root.hidePermissionsBar();
z:101
}
}
}
WebView {
id: webview
url: "https://highfidelity.com/"
profile: FileTypeProfile;
// Create a global EventBridge object for raiseAndLowerKeyboard.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.Deferred
worldId: WebEngineScript.MainWorld
}
// Detect when may want to raise and lower keyboard.
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
anchors.top: buttons.bottom
anchors.topMargin: 8
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
onFeaturePermissionRequested: {
if (feature == 2) { // QWebEnginePage::MediaAudioCapture
grantFeaturePermission(securityOrigin, feature, true);
} else {
permissionsBar.securityOrigin = securityOrigin;
permissionsBar.feature = feature;
root.showPermissionsBar();
}
}
onLoadingChanged: {
if (loadRequest.status === WebEngineView.LoadSucceededStatus) {
addressBar.text = loadRequest.url
}
root.loadingChanged(loadRequest.status);
}
onWindowCloseRequested: {
root.destroy();
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
desktop.initWebviewProfileHandlers(webview.profile);
}
}
} // item
Keys.onPressed: {
switch(event.key) {
case Qt.Key_L:
if (event.modifiers == Qt.ControlModifier) {
event.accepted = true
addressBar.selectAll()
addressBar.forceActiveFocus()
}
break;
}
}
} // dialog

View file

@ -0,0 +1,50 @@
//
// InfoView.qml
//
// Created by Bradley Austin Davis on 27 Apr 2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.5
import Hifi 1.0 as Hifi
import controlsUit 1.0
import "qrc:////qml//windows" as Windows
Windows.ScrollingWindow {
id: root
width: 800
height: 800
resizable: true
Hifi.InfoView {
id: infoView
width: pane.contentWidth
implicitHeight: pane.scrollHeight
WebView {
id: webview
objectName: "WebView"
anchors.fill: parent
url: infoView.url
}
}
Component.onCompleted: {
centerWindow(root);
}
onVisibleChanged: {
if (visible) {
centerWindow(root);
}
}
function centerWindow() {
desktop.centerOnVisible(root);
}
}

View file

@ -0,0 +1,125 @@
import QtQuick 2.5
import QtWebChannel 1.0
import QtWebEngine 1.5
import "controls"
import controlsUit 1.0 as HifiControls
import "styles" as HifiStyles
import stylesUit 1.0
import "windows"
Item {
id: root
HifiConstants { id: hifi }
HifiStyles.HifiConstants { id: hifistyles }
height: 600
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
property alias url: webview.url
property bool canGoBack: webview.canGoBack
property bool canGoForward: webview.canGoForward
signal loadingChanged(int status)
x: 0
y: 0
function setProfile(profile) {
webview.profile = profile;
}
WebEngineView {
id: webview
objectName: "webEngineView"
x: 0
y: 0
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
profile: HFWebEngineProfile;
property string userScriptUrl: ""
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: webview.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
property string newUrl: ""
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
web.address = url;
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
onLoadingChanged: {
keyboardRaised = false;
punctuationMode = false;
keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
urlAppend(loadRequest.url.toString())
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
onNewViewRequested: {
request.openIn(webView);
}
HifiControls.WebSpinner { }
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_L:
if (event.modifiers == Qt.ControlModifier) {
event.accepted = true
addressBar.selectAll()
addressBar.forceActiveFocus()
}
break;
}
}
}

View file

@ -1,16 +1,14 @@
import QtQuick 2.5
import QtWebChannel 1.0
import QtWebView 1.1
import controlsUit 1.0
import "styles" as HifiStyles
import stylesUit 1.0
import "windows"
ScrollingWindow {
id: root
HifiConstants { id: hifi }
HifiStyles.HifiConstants { id: hifistyles }
//HifiStyles.HifiConstants { id: hifistyles }
title: "Browser"
resizable: true
destroyOnHidden: true
@ -32,7 +30,6 @@ ScrollingWindow {
}
function setProfile(profile) {
webview.profile = profile;
}
function showPermissionsBar(){
@ -44,7 +41,6 @@ ScrollingWindow {
}
function allowPermissions(){
webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true);
hidePermissionsBar();
}
@ -68,7 +64,7 @@ ScrollingWindow {
id: back;
enabled: webview.canGoBack;
text: hifi.glyphs.backward
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goBack() }
}
@ -77,7 +73,7 @@ ScrollingWindow {
id: forward;
enabled: webview.canGoForward;
text: hifi.glyphs.forward
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
@ -86,7 +82,7 @@ ScrollingWindow {
id: reload;
enabled: webview.canGoForward;
text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload
color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText
color: enabled ? hifi.colors.text : hifi.colors.disabledText
size: 48
MouseArea { anchors.fill: parent; onClicked: webview.goForward() }
}
@ -202,43 +198,10 @@ ScrollingWindow {
}
}
WebView {
ProxyWebView {
id: webview
anchors.centerIn: parent
url: "https://highfidelity.com/"
profile: FileTypeProfile;
anchors.top: buttons.bottom
anchors.topMargin: 8
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
onFeaturePermissionRequested: {
if (feature == 2) { // QWebEnginePage::MediaAudioCapture
grantFeaturePermission(securityOrigin, feature, true);
} else {
permissionsBar.securityOrigin = securityOrigin;
permissionsBar.feature = feature;
root.showPermissionsBar();
}
}
onLoadingChanged: {
if (loadRequest.status === WebView.LoadSucceededStatus) {
addressBar.text = loadRequest.url
}
root.loadingChanged(loadRequest.status);
}
onWindowCloseRequested: {
root.destroy();
}
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
desktop.initWebviewProfileHandlers(webview.profile);
}
}
} // item

View file

@ -19,13 +19,12 @@ Windows.ScrollingWindow {
width: 800
height: 800
resizable: true
Hifi.InfoView {
id: infoView
width: pane.contentWidth
implicitHeight: pane.scrollHeight
WebView {
ProxyWebView {
id: webview
objectName: "WebView"
anchors.fill: parent

View file

@ -1,17 +1,11 @@
import QtQuick 2.5
import QtWebChannel 1.0
import QtWebView 1.1
import "controls"
import controlsUit 1.0 as HifiControls
import "styles" as HifiStyles
import stylesUit 1.0
import "windows"
Item {
id: root
HifiConstants { id: hifi }
HifiStyles.HifiConstants { id: hifistyles }
height: 600
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
@ -30,64 +24,9 @@ Item {
webview.profile = profile;
}
WebView {
HifiControls.ProxyWebView {
id: webview
objectName: "webEngineView"
x: 0
y: 0
width: parent.width
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
property string userScriptUrl: ""
property string newUrl: ""
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
// Ensure the JS from the web-engine makes it to our logging
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
web.address = url;
}
onLoadingChanged: {
keyboardRaised = false;
punctuationMode = false;
keyboard.resetShiftMode(false);
// Required to support clicking on "hifi://" links
if (WebView.LoadStartedStatus == loadRequest.status) {
urlAppend(loadRequest.url.toString())
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
onNewViewRequested: {
request.openIn(webView);
}
HifiControls.WebSpinner { }
}
Keys.onPressed: {
switch(event.key) {
case Qt.Key_L:
if (event.modifiers == Qt.ControlModifier) {
event.accepted = true
addressBar.selectAll()
addressBar.forceActiveFocus()
}
break;
}
height: parent.height
}
}

View file

@ -0,0 +1,189 @@
import QtQuick 2.7
import QtWebEngine 1.5
import QtWebChannel 1.0
import QtQuick.Controls 2.2
import stylesUit 1.0 as StylesUIt
Item {
id: flick
property alias url: webViewCore.url
property alias canGoBack: webViewCore.canGoBack
property alias webViewCore: webViewCore
property alias webViewCoreProfile: webViewCore.profile
property string webViewCoreUserAgent
property string userScriptUrl: ""
property string urlTag: "noDownload=false";
signal newViewRequestedCallback(var request)
signal loadingChangedCallback(var loadRequest)
width: parent.width
property bool interactive: false
property bool blurOnCtrlShift: true
StylesUIt.HifiConstants {
id: hifi
}
function stop() {
webViewCore.stop();
}
Timer {
id: delayedUnfocuser
repeat: false
interval: 200
onTriggered: {
// The idea behind this is to delay unfocusing, so that fast lower/raise will not result actual unfocusing.
// Fast lower/raise happens every time keyboard is being re-raised (see the code below in OffscreenQmlSurface::setKeyboardRaised)
//
// if (raised) {
// item->setProperty("keyboardRaised", QVariant(!raised));
// }
//
// item->setProperty("keyboardRaised", QVariant(raised));
//
webViewCore.runJavaScript("if (document.activeElement) document.activeElement.blur();", function(result) {
console.log('unfocus completed: ', result);
});
}
}
function unfocus() {
delayedUnfocuser.start();
}
function stopUnfocus() {
delayedUnfocuser.stop();
}
function onLoadingChanged(loadRequest) {
if (WebEngineView.LoadStartedStatus === loadRequest.status) {
// Required to support clicking on "hifi://" links
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
webViewCore.stop();
}
}
}
if (WebEngineView.LoadFailedStatus === loadRequest.status) {
console.log("Tablet WebEngineView failed to load url: " + loadRequest.url.toString());
}
if (WebEngineView.LoadSucceededStatus === loadRequest.status) {
//disable Chromium's scroll bars
}
}
WebEngineView {
id: webViewCore
width: parent.width
height: parent.height
profile: HFWebEngineProfile;
settings.pluginsEnabled: true
settings.touchIconsEnabled: true
settings.allowRunningInsecureContent: true
// creates a global EventBridge object.
WebEngineScript {
id: createGlobalEventBridge
sourceCode: eventBridgeJavaScriptToInject
injectionPoint: WebEngineScript.DocumentCreation
worldId: WebEngineScript.MainWorld
}
// detects when to raise and lower virtual keyboard
WebEngineScript {
id: raiseAndLowerKeyboard
injectionPoint: WebEngineScript.Deferred
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
worldId: WebEngineScript.MainWorld
}
// User script.
WebEngineScript {
id: userScript
sourceUrl: flick.userScriptUrl
injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished.
worldId: WebEngineScript.MainWorld
}
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
if (webViewCoreUserAgent !== undefined) {
webViewCore.profile.httpUserAgent = webViewCoreUserAgent
} else {
webViewCore.profile.httpUserAgent += " (HighFidelityInterface)";
}
// Ensure the JS from the web-engine makes it to our logging
webViewCore.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
//disable popup
onContextMenuRequested: {
request.accepted = true;
}
onNewViewRequested: {
newViewRequestedCallback(request)
}
// Prior to 5.10, the WebEngineView loading property is true during initial page loading and then stays false
// as in-page javascript adds more html content. However, in 5.10 there is a bug such that adding html turns
// loading true, and never turns it false again. safeLoading provides a workaround, but it should be removed
// when QT fixes this.
property bool safeLoading: false
property bool loadingLatched: false
property var loadingRequest: null
onLoadingChanged: {
webViewCore.loadingRequest = loadRequest;
webViewCore.safeLoading = webViewCore.loading && !loadingLatched;
webViewCore.loadingLatched |= webViewCore.loading;
}
onSafeLoadingChanged: {
flick.onLoadingChanged(webViewCore.loadingRequest)
loadingChangedCallback(webViewCore.loadingRequest)
}
}
AnimatedImage {
//anchoring doesnt works here when changing content size
x: flick.width/2 - width/2
y: flick.height/2 - height/2
source: "../../icons/loader-snake-64-w.gif"
visible: webViewCore.safeLoading && /^(http.*|)$/i.test(webViewCore.url.toString())
playing: visible
z: 10000
}
Keys.onPressed: {
if (blurOnCtrlShift && (event.modifiers & Qt.ShiftModifier) && (event.modifiers & Qt.ControlModifier)) {
webViewCore.focus = false;
}
}
}

View file

@ -1,10 +1,9 @@
import QtQuick 2.7
import QtWebView 1.1
import QtWebChannel 1.0
import QtQuick.Controls 2.2
import stylesUit 1.0 as StylesUIt
import controlsUit 1.0 as ControlsUit
Item {
id: flick
@ -33,130 +32,21 @@ Item {
}
function stop() {
webViewCore.stop();
}
Timer {
id: delayedUnfocuser
repeat: false
interval: 200
onTriggered: {
// The idea behind this is to delay unfocusing, so that fast lower/raise will not result actual unfocusing.
// Fast lower/raise happens every time keyboard is being re-raised (see the code below in OffscreenQmlSurface::setKeyboardRaised)
//
// if (raised) {
// item->setProperty("keyboardRaised", QVariant(!raised));
// }
//
// item->setProperty("keyboardRaised", QVariant(raised));
//
webViewCore.runJavaScript("if (document.activeElement) document.activeElement.blur();", function(result) {
console.log('unfocus completed: ', result);
});
}
}
function unfocus() {
delayedUnfocuser.start();
}
function stopUnfocus() {
delayedUnfocuser.stop();
}
function onLoadingChanged(loadRequest) {
if (WebView.LoadStartedStatus === loadRequest.status) {
// Required to support clicking on "hifi://" links
var url = loadRequest.url.toString();
url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag;
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
webViewCore.stop();
}
}
}
if (WebView.LoadFailedStatus === loadRequest.status) {
console.log("Tablet Web View failed to load url: " + loadRequest.url.toString());
}
if (WebView.LoadSucceededStatus === loadRequest.status) {
//disable Chromium's scroll bars
}
}
WebView {
ControlsUit.ProxyWebView {
id: webViewCore
width: parent.width
height: parent.height
settings.pluginsEnabled: true
settings.touchIconsEnabled: true
settings.allowRunningInsecureContent: true
Component.onCompleted: {
webChannel.registerObject("eventBridge", eventBridge);
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
if (webViewCoreUserAgent !== undefined) {
webViewCore.profile.httpUserAgent = webViewCoreUserAgent
} else {
webViewCore.profile.httpUserAgent += " (HighFidelityInterface)";
}
// Ensure the JS from the web-engine makes it to our logging
webViewCore.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
});
}
onFeaturePermissionRequested: {
grantFeaturePermission(securityOrigin, feature, true);
}
//disable popup
onContextMenuRequested: {
request.accepted = true;
}
onNewViewRequested: {
newViewRequestedCallback(request)
}
// Prior to 5.10, the WebEngineView loading property is true during initial page loading and then stays false
// as in-page javascript adds more html content. However, in 5.10 there is a bug such that adding html turns
// loading true, and never turns it false again. safeLoading provides a workaround, but it should be removed
// when QT fixes this.
property bool safeLoading: false
property bool loadingLatched: false
property var loadingRequest: null
onLoadingChanged: {
webViewCore.loadingRequest = loadRequest;
webViewCore.safeLoading = webViewCore.loading && !loadingLatched;
webViewCore.loadingLatched |= webViewCore.loading;
}
onSafeLoadingChanged: {
flick.onLoadingChanged(webViewCore.loadingRequest)
loadingChangedCallback(webViewCore.loadingRequest)
}
}
AnimatedImage {
//anchoring doesnt works here when changing content size
x: flick.width/2 - width/2
y: flick.height/2 - height/2
source: "../../icons/loader-snake-64-w.gif"
visible: webViewCore.safeLoading && /^(http.*|)$/i.test(webViewCore.url.toString())
playing: visible
z: 10000
}
Keys.onPressed: {
if (blurOnCtrlShift && (event.modifiers & Qt.ShiftModifier) && (event.modifiers & Qt.ControlModifier)) {
webViewCore.focus = false;
}
}
}

View file

@ -0,0 +1,38 @@
//
// WebView.qml
//
// Created by Bradley Austin Davis on 12 Jan 2016
// Copyright 2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.7
import QtWebEngine 1.5
WebEngineView {
id: root
Component.onCompleted: {
console.log("Connecting JS messaging to Hifi Logging")
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
});
}
onLoadingChanged: {
// Required to support clicking on "hifi://" links
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
WebSpinner { }
}

View file

@ -8,37 +8,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
import QtQuick 2.7
import QtWebView 1.1
import "."
WebView {
ProxyWebView {
id: root
Component.onCompleted: {
console.log("Connecting JS messaging to Hifi Logging")
// Ensure the JS from the web-engine makes it to our logging
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
});
}
onLoadingChanged: {
// Required to support clicking on "hifi://" links
if (WebView.LoadStartedStatus == loadRequest.status) {
var url = loadRequest.url.toString();
if (urlHandler.canHandleUrl(url)) {
if (urlHandler.handleUrl(url)) {
root.stop();
}
}
}
}
signal newViewRequested();
signal windowCloseRequested();
signal featurePermissionRequested();
property var profile: null;
WebSpinner { }
}

View file

@ -0,0 +1,30 @@
import QtQuick 2.7
import stylesUit 1.0
Rectangle {
HifiConstants {
id: hifi
}
color: hifi.colors.darkGray
signal onNewViewRequested();
property string url: "";
property bool canGoBack: false
property bool canGoForward: false
property string icon: ""
property var profile: {}
property bool safeLoading: false
property bool loadingLatched: false
property var loadingRequest: null
Text {
anchors.centerIn: parent
text: "This feature is not supported"
font.pixelSize: 32
color: hifi.colors.white
}
}

View file

@ -29,6 +29,7 @@ TextEdit 1.0 TextEdit.qml
TextField 1.0 TextField.qml
ToolTip 1.0 ToolTip.qml
Tree 1.0 Tree.qml
ProxyWebView 1.0 ProxyWebView.qml
VerticalSpacer 1.0 VerticalSpacer.qml
WebGlyphButton 1.0 WebGlyphButton.qml
WebSpinner 1.0 WebSpinner.qml

View file

@ -21,11 +21,10 @@ import "../../../../controls" as HifiControls
import "../" as HifiCommerceCommon
import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere.
Rectangle {
Item {
HifiConstants { id: hifi; }
id: root;
color: hifi.colors.baseGray
property int parentAppTitleBarHeight;
property int parentAppNavBarHeight;
property string currentActiveView: "sendAssetHome";

View file

@ -3,10 +3,13 @@ import Hifi 1.0
import "../../dialogs"
import "../../controls"
import stylesUit 1.0
Item {
Rectangle {
HifiConstants { id: hifi; }
id: tabletRoot
objectName: "tabletRoot"
color: hifi.colors.baseGray
property string username: "Unknown user"
property string usernameShort: "Unknown user"
property var rootMenu;

View file

@ -767,6 +767,11 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
// set the OCULUS_STORE property so the oculus plugin can know if we ran from the Oculus Store
static const auto OCULUS_STORE_ARG = "--oculus-store";
bool isStore = cmdOptionExists(argc, const_cast<const char**>(argv), OCULUS_STORE_ARG);
qApp->setProperty(hifi::properties::OCULUS_STORE, isStore);
// Ignore any previous crashes if running from command line with a test script.
bool inTestMode { false };
for (int i = 0; i < argc; ++i) {
@ -1148,10 +1153,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
qCDebug(interfaceapp) << "[VERSION] We will use DEVELOPMENT global services.";
#endif
// set the OCULUS_STORE property so the oculus plugin can know if we ran from the Oculus Store
static const QString OCULUS_STORE_ARG = "--oculus-store";
bool isStore = arguments().indexOf(OCULUS_STORE_ARG) != -1;
setProperty(hifi::properties::OCULUS_STORE, isStore);
bool isStore = property(hifi::properties::OCULUS_STORE).toBool();
DependencyManager::get<WalletScriptingInterface>()->setLimitedCommerce(isStore); // Or we could make it a separate arg, or if either arg is set, etc. And should this instead by a hifi::properties?
updateHeartbeat();

View file

@ -5300,6 +5300,21 @@ void MyAvatar::releaseGrab(const QUuid& grabID) {
bool tellHandler { false };
_avatarGrabsLock.withWriteLock([&] {
std::map<QUuid, GrabPointer>::iterator itr;
itr = _avatarGrabs.find(grabID);
if (itr != _avatarGrabs.end()) {
GrabPointer grab = itr->second;
if (grab) {
grab->setReleased(true);
bool success;
SpatiallyNestablePointer target = SpatiallyNestable::findByID(grab->getTargetID(), success);
if (target && success) {
target->disableGrab(grab);
}
}
}
if (_avatarGrabData.remove(grabID)) {
_grabsToDelete.push_back(grabID);
tellHandler = true;

View file

@ -59,7 +59,7 @@ void AddressBarDialog::loadHome() {
auto locationBookmarks = DependencyManager::get<LocationBookmarks>();
QString homeLocation = locationBookmarks->addressForBookmark(LocationBookmarks::HOME_BOOKMARK);
if (homeLocation == "") {
homeLocation = DEFAULT_HIFI_ADDRESS;
homeLocation = DEFAULT_HOME_ADDRESS;
}
DependencyManager::get<AddressManager>()->handleLookupString(homeLocation);
}

View file

@ -151,10 +151,10 @@ void AnimBlendLinearMove::setFrameAndPhase(float dt, float alpha, int prevPoseIn
if (_phase < 0.0f) {
_phase = 0.0f;
}
// detect loop trigger events
if (_phase >= 1.0f) {
triggersOut.setTrigger(_id + "Loop");
triggersOut.setTrigger(_id + "OnLoop");
_phase = glm::fract(_phase);
}

View file

@ -209,15 +209,14 @@ public:
void set(const QString& key, const QString& value) { _map[key] = AnimVariant(value); }
void unset(const QString& key) { _map.erase(key); }
void setTrigger(const QString& key) { _triggers.insert(key); }
void clearTriggers() { _triggers.clear(); }
void setTrigger(const QString& key) { _map[key] = AnimVariant(true); }
void setRigToGeometryTransform(const glm::mat4& rigToGeometry) {
_rigToGeometryMat = rigToGeometry;
_rigToGeometryRot = glmExtractRotation(rigToGeometry);
}
void clearMap() { _map.clear(); }
void clearMap() { _map.clear(); _triggers.clear(); }
bool hasKey(const QString& key) const { return _map.find(key) != _map.end(); }
const AnimVariant& get(const QString& key) const {
@ -238,7 +237,7 @@ public:
// For stat debugging.
std::map<QString, QString> toDebugMap() const;
#ifdef NDEBUG
#ifndef NDEBUG
void dump() const {
qCDebug(animation) << "AnimVariantMap =";
for (auto& pair : _map) {

View file

@ -1207,9 +1207,7 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons
_networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
}
_lastAnimVars = _animVars;
_animVars.clearTriggers();
_animVars = triggersOut;
_networkVars.clearTriggers();
_networkVars = networkTriggersOut;
_lastContext = context;
}

View file

@ -412,6 +412,9 @@ void Avatar::accumulateGrabPositions(std::map<QUuid, GrabLocationAccumulator>& g
if (!grab || !grab->getActionID().isNull()) {
continue; // the accumulated value isn't used, in this case.
}
if (grab->getReleased()) {
continue;
}
glm::vec3 jointTranslation = getAbsoluteJointTranslationInObjectFrame(grab->getParentJointIndex());
glm::quat jointRotation = getAbsoluteJointRotationInObjectFrame(grab->getParentJointIndex());

View file

@ -632,9 +632,11 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
// include jointData if there is room for the most minimal section. i.e. no translations or rotations.
IF_AVATAR_SPACE(PACKET_HAS_JOINT_DATA, AvatarDataPacket::minJointDataSize(numJoints)) {
// Allow for faux joints + translation bit-vector:
const ptrdiff_t minSizeForJoint = sizeof(AvatarDataPacket::SixByteQuat)
+ jointBitVectorSize + AvatarDataPacket::FAUX_JOINTS_SIZE;
// Minimum space required for another rotation joint -
// size of joint + following translation bit-vector + translation scale + faux joints:
const ptrdiff_t minSizeForJoint = sizeof(AvatarDataPacket::SixByteQuat) + jointBitVectorSize +
sizeof(float) + AvatarDataPacket::FAUX_JOINTS_SIZE;
auto startSection = destinationBuffer;
// compute maxTranslationDimension before we send any joint data.
@ -724,6 +726,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
const JointData& data = joints[i];
const JointData& last = lastSentJointData[i];
// Note minSizeForJoint is conservative since there isn't a following bit-vector + scale.
if (packetEnd - destinationBuffer >= minSizeForJoint) {
if (!data.translationIsDefaultPose) {
if (sendAll || last.translationIsDefaultPose || (!cullSmallChanges && last.translation != data.translation)

View file

@ -1048,7 +1048,7 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool
QString scriptUrl = entity->getScript();
if ((shouldLoad && unloadFirst) || scriptUrl.isEmpty()) {
if (_entitiesScriptEngine) {
_entitiesScriptEngine->unloadEntityScript(entityID);
_entitiesScriptEngine->unloadEntityScript(entityID);
}
entity->scriptHasUnloaded();
}

View file

@ -59,6 +59,7 @@ public:
virtual bool isReadyForAdd() const { return true; }
bool isActive() { return _active; }
void deactivate() { _active = false; }
virtual void removeFromSimulation(EntitySimulationPointer simulation) const = 0;
virtual EntityItemWeakPointer getOwnerEntity() const = 0;

View file

@ -3506,3 +3506,13 @@ void EntityItem::removeGrab(GrabPointer grab) {
}
disableNoBootstrap();
}
void EntityItem::disableGrab(GrabPointer grab) {
QUuid actionID = grab->getActionID();
if (!actionID.isNull()) {
EntityDynamicPointer action = _grabActions.value(actionID);
if (action) {
action->deactivate();
}
}
}

View file

@ -561,6 +561,7 @@ public:
virtual void addGrab(GrabPointer grab) override;
virtual void removeGrab(GrabPointer grab) override;
virtual void disableGrab(GrabPointer grab) override;
signals:
void requestRenderUpdate();

View file

@ -30,7 +30,8 @@
#include "UserActivityLogger.h"
#include "udt/PacketHeaders.h"
const QString DEFAULT_HIFI_ADDRESS = "file:///~/serverless/tutorial.json";
const QString DEFAULT_HIFI_ADDRESS = "hifi://welcome";
const QString DEFAULT_HOME_ADDRESS = "file:///~/serverless/tutorial.json";
const QString REDIRECT_HIFI_ADDRESS = "file:///~/serverless/redirect.json";
const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager";
const QString SETTINGS_CURRENT_ADDRESS_KEY = "address";

View file

@ -24,6 +24,7 @@
extern const QString DEFAULT_HIFI_ADDRESS;
extern const QString REDIRECT_HIFI_ADDRESS;
extern const QString DEFAULT_HOME_ADDRESS;
const QString SANDBOX_HIFI_ADDRESS = "hifi://localhost";
const QString INDEX_PATH = "/";

View file

@ -115,17 +115,30 @@ void EntityMotionState::updateServerPhysicsVariables() {
}
void EntityMotionState::handleDeactivation() {
// copy _server data to entity
Transform localTransform = _entity->getLocalTransform();
localTransform.setTranslation(_serverPosition);
localTransform.setRotation(_serverRotation);
_entity->setLocalTransformAndVelocities(localTransform, ENTITY_ITEM_ZERO_VEC3, ENTITY_ITEM_ZERO_VEC3);
// and also to RigidBody
btTransform worldTrans;
worldTrans.setOrigin(glmToBullet(_entity->getWorldPosition()));
worldTrans.setRotation(glmToBullet(_entity->getWorldOrientation()));
_body->setWorldTransform(worldTrans);
// no need to update velocities... should already be zero
if (_entity->getDirtyFlags() & (Simulation::DIRTY_TRANSFORM | Simulation::DIRTY_VELOCITIES)) {
// Some non-physical event (script-call or network-packet) has modified the entity's transform and/or velocities
// at the last minute before deactivation --> the values stored in _server* and _body are stale.
// We assume the EntityMotionState is the last to know, so we copy from EntityItem and let things sort themselves out.
Transform localTransform;
_entity->getLocalTransformAndVelocities(localTransform, _serverVelocity, _serverAngularVelocity);
_serverPosition = localTransform.getTranslation();
_serverRotation = localTransform.getRotation();
_serverAcceleration = _entity->getAcceleration();
_serverActionData = _entity->getDynamicData();
_lastStep = ObjectMotionState::getWorldSimulationStep();
} else {
// copy _server data to entity
Transform localTransform = _entity->getLocalTransform();
localTransform.setTranslation(_serverPosition);
localTransform.setRotation(_serverRotation);
_entity->setLocalTransformAndVelocities(localTransform, ENTITY_ITEM_ZERO_VEC3, ENTITY_ITEM_ZERO_VEC3);
// and also to RigidBody
btTransform worldTrans;
worldTrans.setOrigin(glmToBullet(_entity->getWorldPosition()));
worldTrans.setRotation(glmToBullet(_entity->getWorldOrientation()));
_body->setWorldTransform(worldTrans);
// no need to update velocities... should already be zero
}
}
// virtual

View file

@ -26,6 +26,7 @@ ProceduralSkybox::ProceduralSkybox() : graphics::Skybox() {
const int8_t STENCIL_BACKGROUND = 0;
_procedural._opaqueState->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_BACKGROUND, 0xFF, gpu::EQUAL,
gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
_procedural._opaqueState->setDepthTest(gpu::State::DepthTest(false));
}
bool ProceduralSkybox::empty() {

View file

@ -16,6 +16,7 @@
#include <SettingHandle.h>
#include <UserActivityLogger.h>
#include <PathUtils.h>
#include <shared/FileUtils.h>
#include "ScriptEngine.h"
#include "ScriptEngineLogging.h"
@ -476,6 +477,8 @@ ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool i
scriptUrl = normalizeScriptURL(scriptFilename);
}
scriptUrl = QUrl(FileUtils::selectFile(scriptUrl.toString()));
auto scriptEngine = getScriptEngine(scriptUrl);
if (scriptEngine && !scriptEngine->isStopping()) {
return scriptEngine;

View file

@ -26,16 +26,16 @@ public:
void accumulate(glm::vec3 position, glm::quat orientation) {
_position += position;
_orientation = orientation; // XXX
count++;
_count++;
}
glm::vec3 finalizePosition() { return count > 0 ? _position * (1.0f / count) : glm::vec3(0.0f); }
glm::vec3 finalizePosition() { return _count > 0 ? _position * (1.0f / _count) : glm::vec3(0.0f); }
glm::quat finalizeOrientation() { return _orientation; } // XXX
protected:
glm::vec3 _position;
glm::quat _orientation;
int count { 0 };
int _count { 0 };
};
class Grab {
@ -48,7 +48,8 @@ public:
_parentJointIndex(newParentJointIndex),
_hand(newHand),
_positionalOffset(newPositionalOffset),
_rotationalOffset(newRotationalOffset) {}
_rotationalOffset(newRotationalOffset),
_released(false) {}
QByteArray toByteArray();
bool fromByteArray(const QByteArray& grabData);
@ -61,6 +62,7 @@ public:
_positionalOffset = other->_positionalOffset;
_rotationalOffset = other->_rotationalOffset;
_actionID = other->_actionID;
_released = other->_released;
return *this;
}
@ -85,6 +87,9 @@ public:
glm::quat getRotationalOffset() const { return _rotationalOffset; }
void setRotationalOffset(glm::quat rotationalOffset) { _rotationalOffset = rotationalOffset; }
bool getReleased() const { return _released; }
void setReleased(bool value) { _released = value; }
protected:
QUuid _actionID; // if an action is created in bullet for this grab, this is the ID
QUuid _ownerID; // avatar ID of grabber
@ -93,6 +98,7 @@ protected:
QString _hand; // "left" or "right"
glm::vec3 _positionalOffset; // relative to joint
glm::quat _rotationalOffset; // relative to joint
bool _released { false }; // released and scheduled for deletion
};

View file

@ -1390,7 +1390,12 @@ void SpatiallyNestable::removeGrab(GrabPointer grab) {
bool SpatiallyNestable::hasGrabs() {
bool result { false };
_grabsLock.withReadLock([&] {
result = !_grabs.isEmpty();
foreach (const GrabPointer &grab, _grabs) {
if (grab && !grab->getReleased()) {
result = true;
break;
}
}
});
return result;
}

View file

@ -218,6 +218,7 @@ public:
virtual void addGrab(GrabPointer grab);
virtual void removeGrab(GrabPointer grab);
virtual void disableGrab(GrabPointer grab) {};
bool hasGrabs();
virtual QUuid getEditSenderID();
@ -241,7 +242,7 @@ protected:
quint64 _rotationChanged { 0 };
mutable ReadWriteLockable _grabsLock;
QSet<GrabPointer> _grabs;
QSet<GrabPointer> _grabs; // upon this thing
private:
SpatiallyNestable() = delete;

View file

@ -30,11 +30,17 @@ const QStringList& FileUtils::getFileSelectors() {
static std::once_flag once;
static QStringList extraSelectors;
std::call_once(once, [] {
#if defined(Q_OS_ANDROID)
//extraSelectors << "android_" HIFI_ANDROID_APP;
#endif
#if defined(USE_GLES)
extraSelectors << "gles";
#endif
#if defined(Q_OS_ANDROID)
extraSelectors << HIFI_ANDROID_APP;
#ifndef Q_OS_ANDROID
extraSelectors << "webengine";
#endif
});
return extraSelectors;

View file

@ -49,6 +49,7 @@
#include <shared/ReadWriteLockable.h>
#include "SecurityImageProvider.h"
#include "shared/FileUtils.h"
#include "types/FileTypeProfile.h"
#include "types/HFWebEngineProfile.h"
#include "types/SoundEffect.h"
@ -237,6 +238,9 @@ void OffscreenQmlSurface::clearFocusItem() {
void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) {
Parent::initializeEngine(engine);
QQmlFileSelector* fileSelector = new QQmlFileSelector(engine);
fileSelector->setExtraSelectors(FileUtils::getFileSelectors());
static std::once_flag once;
std::call_once(once, [] {
qRegisterMetaType<TabletProxy*>();

View file

@ -0,0 +1,118 @@
"use strict";
/* jslint vars: true, plusplus: true */
//
// defaultScripts.js
// examples
//
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var DEFAULT_SCRIPTS_COMBINED = [
"system/request-service.js",
"system/progress.js",
//"system/away.js",
"system/hmd.js",
"system/menu.js",
"system/bubble.js",
"system/pal.js", // "system/mod.js", // older UX, if you prefer
"system/avatarapp.js",
"system/makeUserConnection.js",
"system/tablet-goto.js",
"system/notifications.js",
"system/commerce/wallet.js",
"system/dialTone.js",
"system/firstPersonHMD.js",
"system/tablet-ui/tabletUI.js",
"system/miniTablet.js"
];
var DEFAULT_SCRIPTS_SEPARATE = [
"system/controllers/controllerScripts.js",
//"system/chat.js"
];
if (Window.interstitialModeEnabled) {
// Insert interstitial scripts at front so that they're started first.
DEFAULT_SCRIPTS_COMBINED.splice(0, 0, "system/interstitialPage.js", "system/redirectOverlays.js");
}
// add a menu item for debugging
var MENU_CATEGORY = "Developer > Scripting";
var MENU_ITEM = "Debug defaultScripts.js";
var SETTINGS_KEY = '_debugDefaultScriptsIsChecked';
var previousSetting = Settings.getValue(SETTINGS_KEY);
if (previousSetting === '' || previousSetting === false || previousSetting === 'false') {
previousSetting = false;
}
if (previousSetting === true || previousSetting === 'true') {
previousSetting = true;
}
if (Menu.menuExists(MENU_CATEGORY) && !Menu.menuItemExists(MENU_CATEGORY, MENU_ITEM)) {
Menu.addMenuItem({
menuName: MENU_CATEGORY,
menuItemName: MENU_ITEM,
isCheckable: true,
isChecked: previousSetting,
});
}
function loadSeparateDefaults() {
for (var i in DEFAULT_SCRIPTS_SEPARATE) {
Script.load(DEFAULT_SCRIPTS_SEPARATE[i]);
}
}
function runDefaultsTogether() {
for (var i in DEFAULT_SCRIPTS_COMBINED) {
Script.include(DEFAULT_SCRIPTS_COMBINED[i]);
}
loadSeparateDefaults();
}
function runDefaultsSeparately() {
for (var i in DEFAULT_SCRIPTS_COMBINED) {
Script.load(DEFAULT_SCRIPTS_COMBINED[i]);
}
loadSeparateDefaults();
}
// start all scripts
if (Menu.isOptionChecked(MENU_ITEM)) {
// we're debugging individual default scripts
// so we load each into its own ScriptEngine instance
runDefaultsSeparately();
} else {
// include all default scripts into this ScriptEngine
runDefaultsTogether();
}
function menuItemEvent(menuItem) {
if (menuItem === MENU_ITEM) {
var isChecked = Menu.isOptionChecked(MENU_ITEM);
if (isChecked === true) {
Settings.setValue(SETTINGS_KEY, true);
} else if (isChecked === false) {
Settings.setValue(SETTINGS_KEY, false);
}
Menu.triggerOption("Reload All Scripts");
}
}
function removeMenuItem() {
if (!Menu.isOptionChecked(MENU_ITEM)) {
Menu.removeMenuItem(MENU_CATEGORY, MENU_ITEM);
}
}
Script.scriptEnding.connect(function() {
removeMenuItem();
});
Menu.menuItemEvent.connect(menuItemEvent);

View file

@ -1,7 +1,7 @@
# Declare dependencies
macro (setup_testcase_dependencies)
# link in the shared libraries
link_hifi_libraries(shared animation gpu fbx graphics networking test-utils)
link_hifi_libraries(shared animation gpu fbx hfm graphics networking test-utils)
package_libraries_for_deployment()
endmacro ()

View file

@ -143,7 +143,7 @@ void AnimInverseKinematicsTests::testSingleChain() {
ikDoll.setTargetVars(QString("D"), QString("positionD"), QString("rotationD"), QString("targetTypeD"),
QString("weightD"), 1.0f, flexCoefficients, QString("poleVectorEnabledD"),
QString("poleReferenceVectorD"), QString("poleVectorD"));
AnimNode::Triggers triggers;
AnimVariantMap triggers;
// the IK solution should be:
//
@ -236,7 +236,7 @@ void AnimInverseKinematicsTests::testSingleChain() {
ikDoll.setTargetVars(QString("D"), QString("positionD"), QString("rotationD"), QString("targetTypeD"),
QString("weightD"), 1.0f, flexCoefficients, QString("poleVectorEnabledD"),
QString("poleReferenceVectorD"), QString("poleVectorD"));
AnimNode::Triggers triggers;
AnimVariantMap triggers;
// the IK solution should be:
//

View file

@ -19,6 +19,7 @@
#include <AddressManager.h>
#include <AccountManager.h>
#include <ResourceManager.h>
#include <ResourceRequestObserver.h>
#include <StatTracker.h>
#include <test-utils/QTestExtensions.h>
@ -33,6 +34,7 @@ void AnimTests::initTestCase() {
DependencyManager::set<NodeList>(NodeType::Agent);
DependencyManager::set<ResourceManager>();
DependencyManager::set<AnimationCache>();
DependencyManager::set<ResourceRequestObserver>();
DependencyManager::set<ResourceCacheSharedItems>();
DependencyManager::set<StatTracker>();
}
@ -84,26 +86,26 @@ void AnimTests::testClipEvaulate() {
AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag);
AnimNode::Triggers triggers;
AnimVariantMap triggers;
clip.evaluate(vars, context, framesToSec(10.0f), triggers);
QCOMPARE_WITH_ABS_ERROR(clip._frame, 12.0f, TEST_EPSILON);
// does it loop?
triggers.clear();
triggers.clearMap();
clip.evaluate(vars, context, framesToSec(12.0f), triggers);
QCOMPARE_WITH_ABS_ERROR(clip._frame, 3.0f, TEST_EPSILON); // Note: frame 3 and not 4, because extra frame between start and end.
// did we receive a loop trigger?
QVERIFY(std::find(triggers.begin(), triggers.end(), "myClipNodeOnLoop") != triggers.end());
QVERIFY(triggers.hasKey("myClipNodeOnLoop"));
// does it pause at end?
triggers.clear();
triggers.clearMap();
clip.setLoopFlagVar("FalseVar");
clip.evaluate(vars, context, framesToSec(20.0f), triggers);
QCOMPARE_WITH_ABS_ERROR(clip._frame, 22.0f, TEST_EPSILON);
// did we receive a done trigger?
QVERIFY(std::find(triggers.begin(), triggers.end(), "myClipNodeOnDone") != triggers.end());
QVERIFY(triggers.hasKey("myClipNodeOnDone"));
}
void AnimTests::testClipEvaulateWithVars() {
@ -133,7 +135,7 @@ void AnimTests::testClipEvaulateWithVars() {
clip.setTimeScaleVar("timeScale2");
clip.setLoopFlagVar("loopFlag2");
AnimNode::Triggers triggers;
AnimVariantMap triggers;
clip.evaluate(vars, context, framesToSec(0.1f), triggers);
// verify that the values from the AnimVariantMap made it into the clipNode's
@ -284,11 +286,11 @@ void AnimTests::testAccumulateTime() {
timeScale = 1.0f;
float dt = 1.0f;
QString id = "testNode";
AnimNode::Triggers triggers;
AnimVariantMap triggers;
float loopFlag = true;
float resultFrame = accumulateTime(startFrame, endFrame, timeScale, startFrame, dt, loopFlag, id, triggers);
// a one frame looping animation should NOT trigger onLoop events
QVERIFY(triggers.empty());
QVERIFY(!triggers.hasKey("testNodeOnLoop"));
const uint32_t MAX_TRIGGER_COUNT = 3;
@ -296,45 +298,45 @@ void AnimTests::testAccumulateTime() {
endFrame = 1.1f;
timeScale = 10.0f;
dt = 10.0f;
triggers.clear();
triggers.clearMap();
loopFlag = true;
resultFrame = accumulateTime(startFrame, endFrame, timeScale, startFrame, dt, loopFlag, id, triggers);
// a short animation with a large dt & a large timescale, should only create a MAXIMUM of 3 loop events.
QVERIFY(triggers.size() <= MAX_TRIGGER_COUNT);
// a short animation with a large dt & a large timescale, should generate a onLoop event.
QVERIFY(triggers.hasKey("testNodeOnLoop"));
}
void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFrame, float timeScale) const {
float dt = (1.0f / 30.0f) / timeScale; // sec
QString id = "testNode";
AnimNode::Triggers triggers;
AnimVariantMap triggers;
bool loopFlag = false;
float resultFrame = accumulateTime(startFrame, endFrame, timeScale, startFrame, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == startFrame + 1.0f);
QVERIFY(triggers.empty());
triggers.clear();
QVERIFY(!triggers.hasKey("testNodeOnLoop"));
triggers.clearMap();
resultFrame = accumulateTime(startFrame, endFrame, timeScale, resultFrame, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == startFrame + 2.0f);
QVERIFY(triggers.empty());
triggers.clear();
QVERIFY(!triggers.hasKey("testNodeOnLoop"));
triggers.clearMap();
resultFrame = accumulateTime(startFrame, endFrame, timeScale, resultFrame, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == startFrame + 3.0f);
QVERIFY(triggers.empty());
triggers.clear();
QVERIFY(!triggers.hasKey("testNodeOnLoop"));
triggers.clearMap();
// test onDone trigger and frame clamping.
resultFrame = accumulateTime(startFrame, endFrame, timeScale, endFrame - 1.0f, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == endFrame);
QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnDone");
triggers.clear();
QVERIFY(triggers.hasKey("testNodeOnDone"));
triggers.clearMap();
resultFrame = accumulateTime(startFrame, endFrame, timeScale, endFrame - 0.5f, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == endFrame);
QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnDone");
triggers.clear();
QVERIFY(triggers.hasKey("testNodeOnDone"));
triggers.clearMap();
// test onLoop trigger and looping frame logic
loopFlag = true;
@ -342,26 +344,26 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram
// should NOT trigger loop even though we stop at last frame, because there is an extra frame between end and start frames.
resultFrame = accumulateTime(startFrame, endFrame, timeScale, endFrame - 1.0f, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == endFrame);
QVERIFY(triggers.empty());
triggers.clear();
QVERIFY(!triggers.hasKey("testNodeOnLoop"));
triggers.clearMap();
// now we should hit loop trigger
resultFrame = accumulateTime(startFrame, endFrame, timeScale, resultFrame, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == startFrame);
QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop");
triggers.clear();
QVERIFY(triggers.hasKey("testNodeOnLoop"));
triggers.clearMap();
// should NOT trigger loop, even though we move past the end frame, because of extra frame between end and start.
resultFrame = accumulateTime(startFrame, endFrame, timeScale, endFrame - 0.5f, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == endFrame + 0.5f);
QVERIFY(triggers.empty());
triggers.clear();
QVERIFY(!triggers.hasKey("testNodeOnLoop"));
triggers.clearMap();
// now we should hit loop trigger
resultFrame = accumulateTime(startFrame, endFrame, timeScale, resultFrame, dt, loopFlag, id, triggers);
QVERIFY(resultFrame == startFrame + 0.5f);
QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop");
triggers.clear();
QVERIFY(triggers.hasKey("testNodeOnLoop"));
triggers.clearMap();
}
void AnimTests::testAnimPose() {