From d93828f2f084d7eed463123d92235ac47a66204c Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 21 Dec 2017 11:50:02 -0700 Subject: [PATCH 01/13] Fix an improve currentAPI.js --- interface/resources/qml/CurrentAPI.qml | 617 ++++++++++++++++++ libraries/script-engine/src/ScriptEngines.h | 5 + .../developer/utilities/tools/currentAPI.js | 201 ++++-- 3 files changed, 785 insertions(+), 38 deletions(-) create mode 100644 interface/resources/qml/CurrentAPI.qml diff --git a/interface/resources/qml/CurrentAPI.qml b/interface/resources/qml/CurrentAPI.qml new file mode 100644 index 0000000000..98eb639e50 --- /dev/null +++ b/interface/resources/qml/CurrentAPI.qml @@ -0,0 +1,617 @@ +// +// ScriptAPI.qml +// +// Created by Luis Cuenca on 12/18/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "styles-uit" +import "controls-uit" as HifiControls + +Item { + id: root + width: parent.width + height: parent.height + + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + property var maxUpdateValues: 20 + property var maxReloadValues: 200 + property var apiMembers: [] + property var membersWithValues: [] + property var isReloading: false + property var evaluatingIdx: -1 + property Component scrollSlider + property Component keyboard + + Rectangle { + color: "white" + width: parent.width + height: parent.height + } + + FontLoader { id: ralewayRegular; source: pathToFonts + "fonts/Raleway-Regular.ttf"; } + + Timer { + id: updateList + interval: 200 + repeat: false + running: false + onTriggered: { + scrollSlider.y = 0; + list.contentY = 0; + } + } + + Row { + id: topBar + anchors.left: parent.left + anchors.leftMargin: 8 + width: parent.width + height: 50 + HifiControls.GlyphButton { + id: search + enabled: true + glyph: hifi.glyphs.search + color: hifi.colors.text + size: 48 + width: 50 + height: 50 + onClicked: { + addListElements(searchBar.text); + focus = true; + } + } + + HifiControls.GlyphButton { + id: back; + enabled: true; + glyph: hifi.glyphs.backward + color: hifi.colors.text + size: 48 + width: 30 + height: 50 + anchors.margins: 2 + onClicked: { + var text = searchBar.text; + var chain = text.split("."); + if (chain.length > 2) { + var result = chain[0]+"."; + for (var i = 1; i < chain.length-2; i++) { + result += chain[i] + "."; + } + result += chain[chain.length-2]; + searchBar.text = result; + } else { + searchBar.text = (chain.length > 1) ? chain[0] : ""; + } + if (chain.length > 1) { + addListElements(searchBar.text); + } else { + addListElements(); + } + focus = true; + } + } + + TextField { + id: searchBar + focus: true + font.pixelSize: 16 + width: 2*(parent.width-back.width-search.width-reload.width-update.width-evaluate.width-addMember.width-16)/3 + height: parent.height + font.family: ralewayRegular.name + placeholderText: "Search" + onAccepted: { + console.log("Enter Pressed"); + search.clicked(); + } + onActiveFocusChanged: { + if (activeFocus && HMD.mounted) { + keyboard.raised = true; + } else { + keyboard.raised = false; + } + } + + } + + HifiControls.Button { + id: addMember; + enabled: true; + fontSize: 30 + text: "+" + width: 50 + height: 50 + anchors.margins: 2 + onClicked: { + addNewMember(); + updateList.start(); + focus = true; + } + } + + HifiControls.Button { + id: evaluate; + enabled: true; + text: "Eval" + width: 50 + height: 50 + anchors.margins: 2 + onClicked: { + evaluateMember(); + focus = true; + } + } + TextField { + id: valueBar + focus: true + font.pixelSize: 16 + width: (parent.width-back.width-search.width-reload.width-update.width-evaluate.width-addMember.width-16)/3 + height: parent.height + font.family: ralewayRegular.name + placeholderText: "Value" + textColor: "#4466DD" + anchors.margins: 2 + } + + HifiControls.GlyphButton { + id: reload; + enabled: false; + glyph: hifi.glyphs.reload + color: hifi.colors.text + size: 48 + width: 50 + height: 50 + anchors.margins: 2 + onClicked: { + reloadListValues(); + focus = true; + } + } + + HifiControls.GlyphButton { + id: update; + enabled: false; + glyph: hifi.glyphs.playback_play + size: 48 + width: 50 + height: 50 + anchors.margins: 2 + onClicked: { + if (isReloading) { + update.glyph = hifi.glyphs.playback_play + isReloading = false; + stopReload(); + } else { + update.glyph = hifi.glyphs.stop_square + isReloading = true; + startReload(); + } + focus = true; + } + } + } + + ListModel { + id: memberModel + } + + Component { + id: memberDelegate + + Row { + id: memberRow + property var isMainKey: apiType === "class"; + spacing: 10 + Rectangle { + width: isMainKey ? 20 : 40; + height: parent.height + } + + RalewayRegular { + text: apiMember + size: !isMainKey ? 16 : 22 + MouseArea { + width: list.width + height: parent.height + onClicked: { + searchBar.text = apiType=="function()" ? apiMember + "()" : apiMember; + valueBar.text = !apiValue ? "" : apiValue; + list.currentIndex = index; + evaluatingIdx = index; + } + onDoubleClicked: { + if (apiType === "class") { + addListElements(apiMember+"."); + } else { + isolateElement(evaluatingIdx); + } + + } + } + } + + + RalewayRegular { + text: apiType + size: 14 + color: hifi.colors.baseGrayHighlight + } + + RalewayRegular { + text: !apiValue ? "" : apiValue; + size: 16 + color: "#4466DD" + } + } + } + + + Rectangle { + id: membersBackground + anchors { + left: parent.left; right: parent.right; top: topBar.bottom; bottom: parent.bottom; + margins: hifi.dimensions.contentMargin.x + bottomMargin: hifi.dimensions.contentSpacing.y + 40 + } + color: "white" + radius: 4 + + ListView { + id: list + anchors { + top: parent.top + left: parent.left + right: scrollBar.left + bottom: parent.bottom + margins: 4 + } + clip: true + cacheBuffer: 4000 + model: memberModel + delegate: memberDelegate + highlightMoveDuration: 0 + + highlight: Rectangle { + anchors { + left: parent ? parent.left : undefined + right: parent ? parent.right : undefined + leftMargin: hifi.dimensions.borderWidth + rightMargin: hifi.dimensions.borderWidth + } + color: "#BBDDFF" + } + onMovementStarted: { + scrollSlider.manual = true; + } + onMovementEnded: { + if (list.contentHeight > list.height) { + var range = list.contentY/(list.contentHeight-list.height); + range = range > 1 ? 1 : range; + var idx = Math.round((list.count-1)*range); + scrollSlider.positionSlider(idx); + } + scrollSlider.manual = false; + returnToBounds() + } + } + + Rectangle { + id: scrollBar + + property bool scrolling: list.contentHeight > list.height + + anchors { + top: parent.top + right: parent.right + bottom: parent.bottom + topMargin: 4 + bottomMargin: 4 + } + width: scrolling ? 18 : 0 + radius: 4 + color: hifi.colors.baseGrayShadow + + MouseArea { + anchors.fill: parent + + onClicked: { + var index = scrollSlider.y * (list.count - 1) / (scrollBar.height - scrollSlider.height); + index = Math.round(index); + var scrollAmount = Math.round(list.count/10); + index = index + (mouse.y <= scrollSlider.y ? -scrollAmount : scrollAmount); + if (index < 0) { + index = 0; + } + if (index > list.count - 1) { + index = list.count - 1; + } + scrollSlider.positionSlider(index); + } + } + + Rectangle { + id: scrollSlider + + property var manual: false + + function positionSlider(index){ + y = index*(scrollBar.height - scrollSlider.height)/(list.count - 1); + } + + anchors { + right: parent.right + rightMargin: 3 + } + width: 12 + height: (list.height / list.contentHeight) * list.height + radius: width / 4 + color: "white" + + visible: scrollBar.scrolling; + + onYChanged: { + var index = y * (list.count - 1) / (scrollBar.height - scrollSlider.height); + index = Math.round(index); + if (!manual) { + list.positionViewAtIndex(index, ListView.Visible); + } + } + + MouseArea { + anchors.fill: parent + drag.target: scrollSlider + drag.axis: Drag.YAxis + drag.minimumY: 0 + drag.maximumY: scrollBar.height - scrollSlider.height + } + } + } + + + + } + + HifiControls.GlyphButton { + id: clipboard; + enabled: true; + glyph: hifi.glyphs.scriptNew + size: 38 + width: 50 + height: 50 + anchors.left: parent.left + anchors.bottom: parent.bottom + anchors.margins: 2 + anchors.leftMargin: 8 + onClicked: { + var buffer = ""; + for (var i = 0; i < memberModel.count; i++) { + var datarow = memberModel.get(i); + buffer += "\n" + datarow.apiMember + " " + datarow.apiType + " " + datarow.apiValue; + } + Window.copyToClipboard(buffer); + focus = true; + } + } + + HifiControls.Button { + id: debug; + enabled: true; + text: "Debug Script" + width: 120 + height: 50 + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 2 + anchors.rightMargin: 8 + onClicked: { + sendToScript({type: "selectScript"}); + } + } + + HifiControls.Keyboard { + id: keyboard; + raised: false; + anchors { + bottom: parent.bottom; + left: parent.left; + right: parent.right; + } + // "\ue02b" + Keys.onPressed: { + console.log(event.nativeScanCode); + if (event.key == Qt.Key_Left) { + keyboard.raised = false; + } + } + } + + + + function addNewMember() { + apiMembers.push({member: searchBar.text, type: "user", value: valueBar.text, hasValue: true}); + var data = {'memberIndex': apiMembers.length-1, 'apiMember': searchBar.text, 'apiType':"user", 'apiValue': valueBar.text}; + memberModel.insert(0, data); + computeMembersWithValues(); + } + + function evaluateMember() { + sendToScript({type: "evaluateMember", data:{member: searchBar.text, index: evaluatingIdx}}); + } + + function getValuesToRefresh() { + var valuesToRefresh = []; + for (var i = 0; i < membersWithValues.length; i++) { + var index = membersWithValues[i]; + var row = memberModel.get(index); + valuesToRefresh.push({index: index, member: (row.apiType == "function()") ? row.apiMember+"()" : row.apiMember, value: row.apiValue}); + } + return valuesToRefresh; + } + + + function reloadListValues(){ + var valuesToRefresh = getValuesToRefresh(); + sendToScript({type: "refreshValues", data:valuesToRefresh}); + } + + function startReload(){ + var valuesToRefresh = getValuesToRefresh(); + sendToScript({type: "startRefreshValues", data:valuesToRefresh}); + } + + function stopReload(){ + sendToScript({type: "stopRefreshValues"}); + } + + function refreshValues(data) { + var buffer = ""; + for (var i = 0; i < data.length; i++) { + var row = memberModel.get(data[i].index); + row.apiValue = data[i].value; + apiMembers[row.memberIndex].value = data[i].value; + memberModel.set(data[i].index, row); + buffer += "\n" + apiMembers[row.memberIndex].member + " : " + data[i].value; + } + print(buffer); + } + + + function fromScript(message) { + if (message.type === "methods") { + apiMembers = message.data; + if (ScriptDiscoveryService.debugScriptUrl != "") { + addListElements("GlobalDebugger"); + if (memberModel.count == 0) { + addListElements(); + } + } else { + addListElements(); + } + + } else if (message.type === "debugMethods") { + addListElements("GlobalDebugger"); + } else if (message.type === "refreshValues") { + refreshValues(message.data); + } else if (message.type === "evaluateMember") { + valueBar.text = message.data.value; + var selrow = memberModel.get(message.data.index); + if (selrow.apiMember === searchBar.text || selrow.apiMember === searchBar.text + "()") { + selrow.apiValue = message.data.value; + apiMembers[selrow.memberIndex].value = message.data.value; + apiMembers[selrow.memberIndex].hasValue = true; + memberModel.set(message.data.index, selrow); + } + } else if (message.type === "selectScript") { + if (message.data.length > 0) { + ScriptDiscoveryService.debugScriptUrl = message.data; + } + } + } + + + function getFilterPairs(filter){ + var filteredArray = []; + var filterChain; + filterChain = filter.split(" "); + for (var i = 0; i < filterChain.length; i++) { + filterChain[i] = filterChain[i].toUpperCase(); + } + var matchPairs = []; + + for (var i = 0; i < apiMembers.length; i++) { + if (filterChain != undefined) { + var found = 0; + var memberComp = apiMembers[i].member.toUpperCase(); + for (var j = 0; j < filterChain.length; j++) { + found += memberComp.indexOf(filterChain[j]) >= 0 ? 1 : 0; + } + if (found === 0) { + continue; + } + matchPairs.push({index: i, found: found, member: apiMembers[i].member}); + } + } + + matchPairs.sort(function(a, b){ + if(a.found > b.found) return -1; + if(a.found < b.found) return 1; + if(a.member > b.member) return 1; + if(a.member < b.member) return -1; + return 0; + }); + + return matchPairs; + } + + function isolateElement(index) { + var oldElement = memberModel.get(index); + var newElement = {memberIndex: oldElement.memberIndex, apiMember: oldElement.apiMember, apiType: oldElement.apiType, apiValue: oldElement.apiValue}; + membersWithValues = apiMembers[oldElement.memberIndex].hasValue ? [0] : []; + memberModel.remove(0, memberModel.count); + memberModel.append(newElement); + } + + function computeMembersWithValues() { + membersWithValues = []; + for (var i = 0; i < memberModel.count; i++) { + var idx = memberModel.get(i).memberIndex; + if (apiMembers[idx].hasValue) { + membersWithValues.push(i); + } + } + update.enabled = membersWithValues.length <= maxUpdateValues; + reload.enabled = membersWithValues.length <= maxReloadValues; + } + + function addListElements(filter) { + valueBar.text = ""; + memberModel.remove(0, memberModel.count); + + var filteredArray = (filter != undefined) ? [] : apiMembers; + var matchPairs; + if (filter != undefined) { + matchPairs = getFilterPairs(filter); + for (var i = 0; i < matchPairs.length; i++) { + if (matchPairs[i].found < matchPairs[0].found) { + break; + } + var idx = matchPairs[i].index; + filteredArray.push(apiMembers[idx]); + } + } + + for (var i = 0; i < filteredArray.length; i++) { + var data = {'memberIndex': matchPairs ? matchPairs[i].index : i, + 'apiMember': filteredArray[i].member, + 'apiType': filteredArray[i].type, + 'apiValue': filteredArray[i].value}; + + memberModel.append(data); + } + + computeMembersWithValues(); + + if (isReloading) { + update.glyph = hifi.glyphs.playback_play + isReloading = false; + stopReload(); + } + + if (memberModel.count > 0) { + scrollSlider.y = 0; + list.contentY = 0; + } + } + + signal sendToScript(var message); +} \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h index f2b0105be1..0f807b08cf 100644 --- a/libraries/script-engine/src/ScriptEngines.h +++ b/libraries/script-engine/src/ScriptEngines.h @@ -31,6 +31,7 @@ class ScriptEngines : public QObject, public Dependency { Q_PROPERTY(ScriptsModel* scriptsModel READ scriptsModel CONSTANT) Q_PROPERTY(ScriptsModelFilter* scriptsModelFilter READ scriptsModelFilter CONSTANT) + Q_PROPERTY(QString debugScriptUrl READ getDebugScriptUrl WRITE setDebugScriptUrl) public: using ScriptInitializer = std::function; @@ -41,6 +42,9 @@ public: void loadScripts(); void saveScripts(); + QString getDebugScriptUrl() { return _debugScriptUrl; }; + void setDebugScriptUrl(const QString& url) { _debugScriptUrl = url; }; + QString getScriptsLocation() const; void loadDefaultScripts(); void setScriptsLocation(const QString& scriptsLocation); @@ -117,6 +121,7 @@ protected: std::atomic _isStopped { false }; std::atomic _isReloading { false }; bool _defaultScriptsLocationOverridden { false }; + QString _debugScriptUrl; }; QUrl normalizeScriptURL(const QUrl& rawScriptURL); diff --git a/scripts/developer/utilities/tools/currentAPI.js b/scripts/developer/utilities/tools/currentAPI.js index cb9f152794..f282c2dba9 100644 --- a/scripts/developer/utilities/tools/currentAPI.js +++ b/scripts/developer/utilities/tools/currentAPI.js @@ -1,42 +1,167 @@ -// -// currentAPI.js -// examples -// -// Created by Clément Brisset on 5/30/14. -// 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 -// +(function(){ + var array = []; + var mainKeys = Object.keys(this); + var qml = Script.resourcesPath() + '/qml/CurrentAPI.qml'; + var needsUpdate = false; + var updateTime = 20; + var updateData = []; + var deltaTime = 0; + var maxUpdatingMethods = 20; + var scriptPath = ""; + + if (ScriptDiscoveryService.debugScriptUrl != "") { + Script.include(ScriptDiscoveryService.debugScriptUrl); + } + + var window = new OverlayWindow({ + title: 'API methods', + source: qml, + width: 1200, + height: 500 + }); -var array = []; -function listKeys(string, object) { - if (string === "listKeys" || string === "array" || string === "buffer" || string === "i") { - return; - } - - if (typeof(object) !== "object" || object === null) { - array.push(string + " " + typeof(object)); - return; - } - - var keys = Object.keys(object); - for (var i = 0; i < keys.length; ++i) { - if (string === "") { - listKeys(keys[i], object[keys[i]]); - } else if (keys[i] !== "parent") { - listKeys(string + "." + keys[i], object[keys[i]]); - } - } -} + window.closed.connect(function () { + Script.stop(); + }); -listKeys("", this); -array.sort(); + function addMainKeys(){ + var keys = Object.keys(this); + for (var i = 0; i < keys.length; i++) { + array.push({member:keys[i] , type: "class"}); + } + } -var buffer = "\n======= JS API list ======="; -for (var i = 0; i < array.length; ++i) { - buffer += "\n" + array[i]; -} -buffer += "\n========= API END =========\n"; + function memberHasValue(member, type) { + if (type === "function()") { + if (member.indexOf(".has") < 0 && member.indexOf(".is") < 0) { + return false; + } + if (member.indexOf("indow") < 0) { + return true; + } + } else if (type === "boolean" || type === "string" || type === "number" || type === "user") { + return true; + } + return false; + } + + function listKeys(string, object) { + if (string === "listKeys" || string === "array" || string === "buffer" || string === "i") { + return; + } + + if (typeof(object) !== "object" || object === null) { + var type = typeof(object); + if (type === "function") { + chain = string.split("("); + if (chain.length > 1) { + string = chain[0]; + type = "function(" + chain[1]; + } + } + var value = ""; + var hasValue = false; + if (memberHasValue(string, type)){ + var evalstring = type === "function()" ? string+"()" : string; + try{ + value = "" + eval(evalstring); + hasValue = true; + } catch(e) { + value = "Error evaluating"; + } + } + array.push({member:string , type: type, value: value, hasValue: hasValue}); + return; + } + + var keys = Object.keys(object); + for (var i = 0; i < keys.length; ++i) { + if (string === "") { + listKeys(keys[i], object[keys[i]]); + } else if (keys[i] !== "parent") { + listKeys(string + "." + keys[i], object[keys[i]]); + } + } + } + + function findMethods(addon, object, addkeys) { + array = []; + var string = addkeys ? "" : addon+"."; + listKeys(string, object); + if (addkeys) { + addMainKeys(); + } + array.sort(function(a, b){ + if(a.member < b.member) return -1; + if(a.member > b.member) return 1; + return 0; + }); + }; + + findMethods("", this, true); + window.sendToQml({type:"methods", data:array}); + + window.fromQml.connect(function(message){ + if (message.type == "refreshValues") { + updateData = message.data; + updateValues(); + } else if (message.type == "startRefreshValues") { + updateData = message.data; + if (updateData.length > maxUpdatingMethods) { + updateData = message.data; + updateValues(); + } else { + needsUpdate = true; + deltaTime = updateTime; + } + } else if (message.type == "stopRefreshValues") { + needsUpdate = false; + deltaTime = 0; + } else if (message.type == "evaluateMember") { + var value = "" + try { + value = "" + eval(message.data.member); + } catch(e) { + value = "Error evaluating" + } + window.sendToQml({type:"evaluateMember", data:{value:value, index:message.data.index}}); + } else if (message.type == "selectScript") { + scriptPath = Window.browse("Select script to debug", "*.js", "JS files(*.js)"); + if (scriptPath) { + ScriptDiscoveryService.stopScript(Paths.defaultScripts + "/developer/utilities/tools/currentAPI.js", true); + } + } + }); + + function updateValues() { + for (var i = 0; i < updateData.length; i++) { + try { + updateData[i].value = "" + eval(updateData[i].member); + } catch(e) { + updateData[i].value = "Error evaluating" + } + } + window.sendToQml({type: "refreshValues", data: updateData}); + } + + Script.update.connect(function(){ + deltaTime++; + if (deltaTime > updateTime) { + deltaTime = 0; + if (needsUpdate) { + updateValues(); + } + } + }); + + Script.scriptEnding.connect(function(){ + if (!scriptPath || scriptPath.length == 0) { + ScriptDiscoveryService.debugScriptUrl = ""; + } else { + ScriptDiscoveryService.debugScriptUrl = scriptPath; + } + console.log("done running"); + window.close(); + }); +}()); -print(buffer); From 54297e00a8038c3f6e9e15d0f53be85918ee9209 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 21 Dec 2017 12:48:21 -0700 Subject: [PATCH 02/13] button size fix --- interface/resources/qml/CurrentAPI.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/resources/qml/CurrentAPI.qml b/interface/resources/qml/CurrentAPI.qml index 98eb639e50..735cbdbab5 100644 --- a/interface/resources/qml/CurrentAPI.qml +++ b/interface/resources/qml/CurrentAPI.qml @@ -127,7 +127,6 @@ Item { HifiControls.Button { id: addMember; enabled: true; - fontSize: 30 text: "+" width: 50 height: 50 From 38bfddf78647d8e0c1ce9af533f5348fe86e4201 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 21 Dec 2017 16:26:06 -0700 Subject: [PATCH 03/13] Added filter for QT autogenerated functions and integrated it to Developers menu --- interface/resources/qml/CurrentAPI.qml | 50 ++- interface/src/Menu.cpp | 8 + .../developer/utilities/tools/currentAPI.js | 324 +++++++++--------- 3 files changed, 215 insertions(+), 167 deletions(-) diff --git a/interface/resources/qml/CurrentAPI.qml b/interface/resources/qml/CurrentAPI.qml index 735cbdbab5..45cf09925a 100644 --- a/interface/resources/qml/CurrentAPI.qml +++ b/interface/resources/qml/CurrentAPI.qml @@ -18,10 +18,7 @@ Item { width: parent.width height: parent.height - - property bool keyboardEnabled: false - property bool keyboardRaised: false - property bool punctuationMode: false + property var hideQtMethods: true property var maxUpdateValues: 20 property var maxReloadValues: 200 @@ -31,7 +28,7 @@ Item { property var evaluatingIdx: -1 property Component scrollSlider property Component keyboard - + Rectangle { color: "white" width: parent.width @@ -375,9 +372,6 @@ Item { } } } - - - } HifiControls.GlyphButton { @@ -417,6 +411,30 @@ Item { } } + HifiControls.CheckBox { + id: hideQt + boxSize: 25 + boxRadius: 3 + checked: true + anchors.left: clipboard.right + anchors.leftMargin: 8 + anchors.verticalCenter: clipboard.verticalCenter + anchors.margins: 2 + onClicked: { + hideQtMethods = checked; + addListElements(); + } + } + + HifiControls.Label { + id: hideLabel + anchors.left: hideQt.right + anchors.verticalCenter: clipboard.verticalCenter + anchors.margins: 2 + font.pixelSize: 15 + text: "Hide Qt Methods" + } + HifiControls.Keyboard { id: keyboard; raised: false; @@ -425,7 +443,7 @@ Item { left: parent.left; right: parent.right; } - // "\ue02b" + Keys.onPressed: { console.log(event.nativeScanCode); if (event.key == Qt.Key_Left) { @@ -433,8 +451,6 @@ Item { } } } - - function addNewMember() { apiMembers.push({member: searchBar.text, type: "user", value: valueBar.text, hasValue: true}); @@ -595,7 +611,17 @@ Item { 'apiType': filteredArray[i].type, 'apiValue': filteredArray[i].value}; - memberModel.append(data); + if (hideQtMethods) { + var chain = data.apiMember.split("."); + var method = chain[chain.length-1]; + if (method != "destroyed" && + method != "objectName" && + method != "objectNameChanged") { + memberModel.append(data); + } + } else { + memberModel.append(data); + } } computeMembersWithValues(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9bbb72357b..25148f1d23 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -757,6 +757,14 @@ Menu::Menu() { // Developer > Stats addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats); + // Developer > API Debugger + action = addActionToQMenuAndActionHash(developerMenu, "API Debugger"); + connect(action, &QAction::triggered, [] { + auto scriptEngines = DependencyManager::get(); + QUrl defaultScriptsLoc = PathUtils::defaultScriptsLocation(); + defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "developer/utilities/tools/currentAPI.js"); + scriptEngines->loadScript(defaultScriptsLoc.toString()); + }); #if 0 /// -------------- REMOVED FOR NOW -------------- addDisabledActionAndSeparator(navigateMenu, "History"); diff --git a/scripts/developer/utilities/tools/currentAPI.js b/scripts/developer/utilities/tools/currentAPI.js index f282c2dba9..175b84b8d9 100644 --- a/scripts/developer/utilities/tools/currentAPI.js +++ b/scripts/developer/utilities/tools/currentAPI.js @@ -1,167 +1,181 @@ +// +// currentAPI.js +// examples +// +// Created by Clément Brisset on 5/30/14. +// 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 +// + + (function(){ - var array = []; - var mainKeys = Object.keys(this); - var qml = Script.resourcesPath() + '/qml/CurrentAPI.qml'; - var needsUpdate = false; - var updateTime = 20; - var updateData = []; - var deltaTime = 0; - var maxUpdatingMethods = 20; - var scriptPath = ""; - - if (ScriptDiscoveryService.debugScriptUrl != "") { - Script.include(ScriptDiscoveryService.debugScriptUrl); - } - - var window = new OverlayWindow({ - title: 'API methods', - source: qml, - width: 1200, - height: 500 - }); + var array = []; + var mainKeys = Object.keys(this); + var qml = Script.resourcesPath() + '/qml/CurrentAPI.qml'; + var needsUpdate = false; + var updateTime = 20; + var updateData = []; + var deltaTime = 0; + var maxUpdatingMethods = 20; + var scriptPath = ""; + + if (ScriptDiscoveryService.debugScriptUrl != "") { + Script.include(ScriptDiscoveryService.debugScriptUrl); + } + + var window = new OverlayWindow({ + title: 'API Debugger', + source: qml, + width: 1200, + height: 500 + }); - window.closed.connect(function () { - Script.stop(); - }); + window.closed.connect(function () { + Script.stop(); + }); - function addMainKeys(){ - var keys = Object.keys(this); - for (var i = 0; i < keys.length; i++) { - array.push({member:keys[i] , type: "class"}); - } - } + function addMainKeys(){ + var keys = Object.keys(this); + for (var i = 0; i < keys.length; i++) { + array.push({member:keys[i] , type: "class"}); + } + } - function memberHasValue(member, type) { - if (type === "function()") { - if (member.indexOf(".has") < 0 && member.indexOf(".is") < 0) { - return false; - } - if (member.indexOf("indow") < 0) { - return true; - } - } else if (type === "boolean" || type === "string" || type === "number" || type === "user") { - return true; - } - return false; - } + function memberHasValue(member, type) { + if (type === "function()") { + if (member.indexOf(".has") < 0 && member.indexOf(".is") < 0 && member.indexOf(".get") < 0) { + return false; + } + if (member.indexOf("indow") < 0) { + return true; + } + } else if (type === "boolean" || type === "string" || type === "number" || type === "user") { + return true; + } + return false; + } - function listKeys(string, object) { - if (string === "listKeys" || string === "array" || string === "buffer" || string === "i") { - return; - } - - if (typeof(object) !== "object" || object === null) { - var type = typeof(object); - if (type === "function") { - chain = string.split("("); - if (chain.length > 1) { - string = chain[0]; - type = "function(" + chain[1]; - } - } - var value = ""; - var hasValue = false; - if (memberHasValue(string, type)){ - var evalstring = type === "function()" ? string+"()" : string; - try{ - value = "" + eval(evalstring); - hasValue = true; - } catch(e) { - value = "Error evaluating"; - } - } - array.push({member:string , type: type, value: value, hasValue: hasValue}); - return; - } - - var keys = Object.keys(object); - for (var i = 0; i < keys.length; ++i) { - if (string === "") { - listKeys(keys[i], object[keys[i]]); - } else if (keys[i] !== "parent") { - listKeys(string + "." + keys[i], object[keys[i]]); - } - } - } + function listKeys(string, object) { + if (string === "listKeys" || string === "array" || string === "buffer" || string === "i") { + return; + } + + if (typeof(object) !== "object" || object === null) { + var type = typeof(object); + if (type === "function") { + chain = string.split("("); + if (chain.length > 1) { + string = chain[0]; + type = "function(" + chain[1]; + } else { + type = "function()"; + } + } + var value = ""; + var hasValue = false; + if (memberHasValue(string, type)){ + var evalstring = type === "function()" ? string+"()" : string; + try{ + value = "" + eval(evalstring); + hasValue = true; + } catch(e) { + value = "Error evaluating"; + } + } + array.push({member:string , type: type, value: value, hasValue: hasValue}); + return; + } + + var keys = Object.keys(object); + for (var i = 0; i < keys.length; ++i) { + if (string === "") { + listKeys(keys[i], object[keys[i]]); + } else if (keys[i] !== "parent") { + listKeys(string + "." + keys[i], object[keys[i]]); + } + } + } - function findMethods(addon, object, addkeys) { - array = []; - var string = addkeys ? "" : addon+"."; - listKeys(string, object); - if (addkeys) { - addMainKeys(); - } - array.sort(function(a, b){ - if(a.member < b.member) return -1; - if(a.member > b.member) return 1; - return 0; - }); - }; + function findMethods(addon, object, addkeys) { + array = []; + var string = addkeys ? "" : addon+"."; + listKeys(string, object); + if (addkeys) { + addMainKeys(); + } + array.sort(function(a, b){ + if(a.member < b.member) return -1; + if(a.member > b.member) return 1; + return 0; + }); + }; - findMethods("", this, true); - window.sendToQml({type:"methods", data:array}); + findMethods("", this, true); + window.sendToQml({type:"methods", data:array}); - window.fromQml.connect(function(message){ - if (message.type == "refreshValues") { - updateData = message.data; - updateValues(); - } else if (message.type == "startRefreshValues") { - updateData = message.data; - if (updateData.length > maxUpdatingMethods) { - updateData = message.data; - updateValues(); - } else { - needsUpdate = true; - deltaTime = updateTime; - } - } else if (message.type == "stopRefreshValues") { - needsUpdate = false; - deltaTime = 0; - } else if (message.type == "evaluateMember") { - var value = "" - try { - value = "" + eval(message.data.member); - } catch(e) { - value = "Error evaluating" - } - window.sendToQml({type:"evaluateMember", data:{value:value, index:message.data.index}}); - } else if (message.type == "selectScript") { - scriptPath = Window.browse("Select script to debug", "*.js", "JS files(*.js)"); - if (scriptPath) { - ScriptDiscoveryService.stopScript(Paths.defaultScripts + "/developer/utilities/tools/currentAPI.js", true); - } - } - }); + window.fromQml.connect(function(message){ + if (message.type == "refreshValues") { + updateData = message.data; + updateValues(); + } else if (message.type == "startRefreshValues") { + updateData = message.data; + if (updateData.length > maxUpdatingMethods) { + updateData = message.data; + updateValues(); + } else { + needsUpdate = true; + deltaTime = updateTime; + } + } else if (message.type == "stopRefreshValues") { + needsUpdate = false; + deltaTime = 0; + } else if (message.type == "evaluateMember") { + var value = "" + try { + value = "" + eval(message.data.member); + } catch(e) { + value = "Error evaluating" + } + window.sendToQml({type:"evaluateMember", data:{value:value, index:message.data.index}}); + } else if (message.type == "selectScript") { + scriptPath = Window.browse("Select script to debug", "*.js", "JS files(*.js)"); + if (scriptPath) { + ScriptDiscoveryService.stopScript(Paths.defaultScripts + "/developer/utilities/tools/currentAPI.js", true); + } + } + }); - function updateValues() { - for (var i = 0; i < updateData.length; i++) { - try { - updateData[i].value = "" + eval(updateData[i].member); - } catch(e) { - updateData[i].value = "Error evaluating" - } - } - window.sendToQml({type: "refreshValues", data: updateData}); - } + function updateValues() { + for (var i = 0; i < updateData.length; i++) { + try { + updateData[i].value = "" + eval(updateData[i].member); + } catch(e) { + updateData[i].value = "Error evaluating" + } + } + window.sendToQml({type: "refreshValues", data: updateData}); + } - Script.update.connect(function(){ - deltaTime++; - if (deltaTime > updateTime) { - deltaTime = 0; - if (needsUpdate) { - updateValues(); - } - } - }); - - Script.scriptEnding.connect(function(){ - if (!scriptPath || scriptPath.length == 0) { - ScriptDiscoveryService.debugScriptUrl = ""; - } else { - ScriptDiscoveryService.debugScriptUrl = scriptPath; - } - console.log("done running"); - window.close(); - }); + Script.update.connect(function(){ + deltaTime++; + if (deltaTime > updateTime) { + deltaTime = 0; + if (needsUpdate) { + updateValues(); + } + } + }); + + Script.scriptEnding.connect(function(){ + if (!scriptPath || scriptPath.length == 0) { + ScriptDiscoveryService.debugScriptUrl = ""; + } else { + ScriptDiscoveryService.debugScriptUrl = scriptPath; + } + console.log("done running"); + window.close(); + }); }()); From 47038e43495967e5a69c73588bff15ea69e772f7 Mon Sep 17 00:00:00 2001 From: Cain Kilgore Date: Sun, 7 Jan 2018 08:31:36 +0000 Subject: [PATCH 04/13] WL 21664 - Window.innerHeight should not include the menu bar --- .../src/scripting/WindowScriptingInterface.cpp | 16 ++++++++++------ .../src/scripting/WindowScriptingInterface.h | 3 +++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 4b355653b6..7fe7022e47 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -176,10 +176,6 @@ bool WindowScriptingInterface::isPointOnDesktopWindow(QVariant point) { return offscreenUi->isPointOnDesktopWindow(point); } -glm::vec2 WindowScriptingInterface::getDeviceSize() const { - return qApp->getDeviceSize(); -} - /// Makes sure that the reticle is visible, use this in blocking forms that require a reticle and /// might be in same thread as a script that sets the reticle to invisible void WindowScriptingInterface::ensureReticleVisible() const { @@ -391,11 +387,19 @@ QString WindowScriptingInterface::checkVersion() { } int WindowScriptingInterface::getInnerWidth() { - return qApp->getWindow()->geometry().width(); + return qApp->getDeviceSize().x; } int WindowScriptingInterface::getInnerHeight() { - return qApp->getWindow()->geometry().height(); + return qApp->getDeviceSize().y; +} + +int WindowScriptingInterface::getMenuHeight() { + return qApp->getPrimaryMenu()->geometry().height(); +} + +glm::vec2 WindowScriptingInterface::getDeviceSize() const { + return qApp->getDeviceSize(); } int WindowScriptingInterface::getX() { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index d223f95af4..57ada00ed8 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -39,11 +39,14 @@ class WindowScriptingInterface : public QObject, public Dependency { Q_PROPERTY(int innerHeight READ getInnerHeight) Q_PROPERTY(int x READ getX) Q_PROPERTY(int y READ getY) + Q_PROPERTY(int menuHeight READ getMenuHeight) + public: WindowScriptingInterface(); ~WindowScriptingInterface(); int getInnerWidth(); int getInnerHeight(); + int getMenuHeight(); int getX(); int getY(); From 61edd83987dbe2c5629f82b4387439d2f33af42d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 12 Dec 2017 17:02:07 -0800 Subject: [PATCH 05/13] Improve stability for HMD third person avatars Previously there was a hack where the sensor to world matrix was NOT updated in HMD mode if the camera was third person. The reason the hack existed was to make third person camera less nauseating for users. However this had a major drawbacks. It led to avatar hip spasms when the user turned around in the tracked volume, while in third person camera. To fix this issue properly, the hack which prevented updating the sensor to world matrix was removed, and now the third person camera is now computed in sensor space relative to the hmd. --- interface/src/Application.cpp | 30 ++++++++++++++++++------ interface/src/Application.h | 5 +++- interface/src/avatar/MyAvatar.cpp | 11 +++------ interface/src/avatar/MySkeletonModel.cpp | 1 - 4 files changed, 30 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f3c41565f8..2d5ec4c62c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2441,7 +2441,7 @@ void Application::initializeUi() { offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2); } -void Application::updateCamera(RenderArgs& renderArgs) { +void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { PROFILE_RANGE(render, __FUNCTION__); PerformanceTimer perfTimer("updateCamera"); @@ -2456,6 +2456,7 @@ void Application::updateCamera(RenderArgs& renderArgs) { // Using the latter will cause the camera to wobble with idle animations, // or with changes from the face tracker if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { + _thirdPersonHMDCameraBoomValid= false; if (isHMDMode()) { mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); _myCamera.setPosition(extractTranslation(camMat)); @@ -2468,12 +2469,25 @@ void Application::updateCamera(RenderArgs& renderArgs) { } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { if (isHMDMode()) { - auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setOrientation(glm::normalize(glmExtractRotation(hmdWorldMat))); - _myCamera.setPosition(extractTranslation(hmdWorldMat) + - myAvatar->getWorldOrientation() * boomOffset); + + if (!_thirdPersonHMDCameraBoomValid) { + const glm::vec3 CAMERA_OFFSET = glm::vec3(0.0f, 0.0f, 0.7f); + _thirdPersonHMDCameraBoom = cancelOutRollAndPitch(myAvatar->getHMDSensorOrientation()) * CAMERA_OFFSET; + _thirdPersonHMDCameraBoomValid = true; + } + + glm::mat4 thirdPersonCameraSensorToWorldMatrix = myAvatar->getSensorToWorldMatrix(); + + const glm::vec3 cameraPos = myAvatar->getHMDSensorPosition() + _thirdPersonHMDCameraBoom * myAvatar->getBoomLength(); + glm::mat4 sensorCameraMat = createMatFromQuatAndPos(myAvatar->getHMDSensorOrientation(), cameraPos); + glm::mat4 worldCameraMat = thirdPersonCameraSensorToWorldMatrix * sensorCameraMat; + + _myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat))); + _myCamera.setPosition(extractTranslation(worldCameraMat)); } else { + _thirdPersonHMDCameraBoomValid = false; + _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { _myCamera.setPosition(myAvatar->getDefaultEyePosition() @@ -2486,6 +2500,7 @@ void Application::updateCamera(RenderArgs& renderArgs) { } } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _thirdPersonHMDCameraBoomValid= false; if (isHMDMode()) { auto mirrorBodyOrientation = myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)); @@ -2520,6 +2535,7 @@ void Application::updateCamera(RenderArgs& renderArgs) { renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; } else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) { + _thirdPersonHMDCameraBoomValid= false; EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer(); if (cameraEntity != nullptr) { if (isHMDMode()) { @@ -5094,7 +5110,7 @@ void Application::update(float deltaTime) { _postUpdateLambdas.clear(); } - editRenderArgs([this](AppRenderArgs& appRenderArgs) { + editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) { appRenderArgs._headPose= getHMDSensorPose(); auto myAvatar = getMyAvatar(); @@ -5140,7 +5156,7 @@ void Application::update(float deltaTime) { resizeGL(); } - this->updateCamera(appRenderArgs._renderArgs); + this->updateCamera(appRenderArgs._renderArgs, deltaTime); appRenderArgs._eyeToWorld = _myCamera.getTransform(); appRenderArgs._isStereo = false; diff --git a/interface/src/Application.h b/interface/src/Application.h index 479ce919a3..b01e998a21 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -146,7 +146,7 @@ public: void initializeGL(); void initializeUi(); - void updateCamera(RenderArgs& renderArgs); + void updateCamera(RenderArgs& renderArgs, float deltaTime); void paintGL(); void resizeGL(); @@ -695,6 +695,9 @@ private: void startHMDStandBySession(); void endHMDSession(); + glm::vec3 _thirdPersonHMDCameraBoom { 0.0f, 0.0f, -1.0f }; + bool _thirdPersonHMDCameraBoomValid { true }; + QUrl _avatarOverrideUrl; bool _saveAvatarOverrideUrl { false }; QObject* _renderEventHandler{ nullptr }; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 68e417ba1d..e863a58e14 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2799,14 +2799,9 @@ void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) { } bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { - auto cameraMode = qApp->getCamera().getMode(); - if (cameraMode == CAMERA_MODE_THIRD_PERSON) { - return false; - } else { - const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees - glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); - return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; - } + const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees + glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); + return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; } bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 50e0474831..17bce655fd 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -34,7 +34,6 @@ Rig::CharacterControllerState convertCharacterControllerState(CharacterControlle } static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { - glm::mat4 worldToSensorMat = glm::inverse(myAvatar->getSensorToWorldMatrix()); // check for pinned hips. From 0e3913baffd9193cd6db957701a38331cc587fd5 Mon Sep 17 00:00:00 2001 From: Cain Kilgore Date: Tue, 9 Jan 2018 09:07:26 +0000 Subject: [PATCH 06/13] Removed Window.menuHeight --- interface/src/scripting/WindowScriptingInterface.cpp | 4 ---- interface/src/scripting/WindowScriptingInterface.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 7fe7022e47..5677e6b32e 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -394,10 +394,6 @@ int WindowScriptingInterface::getInnerHeight() { return qApp->getDeviceSize().y; } -int WindowScriptingInterface::getMenuHeight() { - return qApp->getPrimaryMenu()->geometry().height(); -} - glm::vec2 WindowScriptingInterface::getDeviceSize() const { return qApp->getDeviceSize(); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 57ada00ed8..3b8412900f 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -39,14 +39,12 @@ class WindowScriptingInterface : public QObject, public Dependency { Q_PROPERTY(int innerHeight READ getInnerHeight) Q_PROPERTY(int x READ getX) Q_PROPERTY(int y READ getY) - Q_PROPERTY(int menuHeight READ getMenuHeight) public: WindowScriptingInterface(); ~WindowScriptingInterface(); int getInnerWidth(); int getInnerHeight(); - int getMenuHeight(); int getX(); int getY(); From f78ee7c167bb6783a9886230ff6cd793e7de19c1 Mon Sep 17 00:00:00 2001 From: Cain Kilgore Date: Tue, 9 Jan 2018 09:44:12 +0000 Subject: [PATCH 07/13] WL 21667 - Window.browseDir() dialog doesn't let user use Esc to cancel --- .../resources/qml/dialogs/FileDialog.qml | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index b9633104d5..c49fa145cd 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -70,7 +70,16 @@ ModalWindow { signal selectedFile(var file); signal canceled(); - + signal selected(int button); + + function click(button) { + clickedButton = button; + selected(button); + destroy(); + } + + property int clickedButton: OriginalDialogs.StandardButton.NoButton; + Component.onCompleted: { console.log("Helper " + helper + " drives " + drives); @@ -628,7 +637,10 @@ ModalWindow { case Qt.Key_Backtab: event.accepted = false; break; - + case Qt.Key_Escape: + event.accepted = true; + root.click(OriginalDialogs.StandardButton.Cancel); + break; default: if (addToPrefix(event)) { event.accepted = true @@ -793,7 +805,11 @@ ModalWindow { case Qt.Key_Home: event.accepted = d.navigateHome(); break; - - } + + case Qt.Key_Escape: + event.accepted = true; + root.click(OriginalDialogs.StandardButton.Cancel); + break; + } } } From a42b0cf485183186c0c1571e8d26c1e23e583633 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 9 Jan 2018 14:58:23 -0800 Subject: [PATCH 08/13] comment out logging --- interface/resources/qml/hifi/tablet/TabletAddressDialog.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 217adc5083..f3cda533e9 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -62,7 +62,8 @@ StackView { var callback = rpcCalls[message.id]; if (!callback) { - console.log('No callback for message fromScript', JSON.stringify(message)); + // FIXME: We often recieve very long messages here, the logging of which is drastically slowing down the main thread + //console.log('No callback for message fromScript', JSON.stringify(message)); return; } delete rpcCalls[message.id]; From c46531296f71644fc63b988513c80be1aa677a2b Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 9 Jan 2018 18:28:54 -0800 Subject: [PATCH 09/13] move key logic from onClicked to onReleased --- interface/resources/qml/controls-uit/Key.qml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controls-uit/Key.qml index b2c720368d..dd77fc92dc 100644 --- a/interface/resources/qml/controls-uit/Key.qml +++ b/interface/resources/qml/controls-uit/Key.qml @@ -45,18 +45,6 @@ Item { } } - onClicked: { - mouse.accepted = true; - Tablet.playSound(TabletEnums.ButtonClick); - - webEntity.synthesizeKeyPress(glyph); - webEntity.synthesizeKeyPress(glyph, mirrorText); - - if (toggle) { - toggled = !toggled; - } - } - onDoubleClicked: { mouse.accepted = true; } @@ -94,6 +82,14 @@ Item { onReleased: { if (containsMouse) { + Tablet.playSound(TabletEnums.ButtonClick); + + webEntity.synthesizeKeyPress(glyph); + webEntity.synthesizeKeyPress(glyph, mirrorText); + + if (toggle) { + toggled = !toggled; + } keyItem.state = "mouseOver"; } else { if (toggled) { From 057c7086374776bc75e6904e913d490ebbb62384 Mon Sep 17 00:00:00 2001 From: Cain Kilgore Date: Wed, 10 Jan 2018 19:24:52 +0000 Subject: [PATCH 10/13] Spaces instead of Tabs (Damnit VS Re-install!) --- .../resources/qml/dialogs/FileDialog.qml | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index c49fa145cd..d2115b5e7e 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -71,14 +71,13 @@ ModalWindow { signal selectedFile(var file); signal canceled(); signal selected(int button); - - function click(button) { - clickedButton = button; - selected(button); - destroy(); + function click(button) { + clickedButton = button; + selected(button); + destroy(); } - property int clickedButton: OriginalDialogs.StandardButton.NoButton; + property int clickedButton: OriginalDialogs.StandardButton.NoButton; Component.onCompleted: { console.log("Helper " + helper + " drives " + drives); @@ -637,10 +636,10 @@ ModalWindow { case Qt.Key_Backtab: event.accepted = false; break; - case Qt.Key_Escape: - event.accepted = true; - root.click(OriginalDialogs.StandardButton.Cancel); - break; + case Qt.Key_Escape: + event.accepted = true; + root.click(OriginalDialogs.StandardButton.Cancel); + break; default: if (addToPrefix(event)) { event.accepted = true @@ -806,10 +805,10 @@ ModalWindow { event.accepted = d.navigateHome(); break; - case Qt.Key_Escape: - event.accepted = true; - root.click(OriginalDialogs.StandardButton.Cancel); - break; + case Qt.Key_Escape: + event.accepted = true; + root.click(OriginalDialogs.StandardButton.Cancel); + break; } } } From ae997928c138416744129769f9af07a40442696e Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 10 Jan 2018 11:51:44 -0800 Subject: [PATCH 11/13] Bug fix to prevent wrists entering the avatar's torso. This was inadvertently disabled in PR #11978. --- interface/src/avatar/MySkeletonModel.cpp | 16 ++++++------ libraries/animation/src/Rig.cpp | 31 ++++++++++++------------ libraries/animation/src/Rig.h | 12 ++++++--- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 8d07a878b9..a8bdafb607 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -106,7 +106,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { if (avatarHeadPose.isValid()) { AnimPose pose(avatarHeadPose.getRotation(), avatarHeadPose.getTranslation()); params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = avatarToRigPose * pose; - params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Head] = true; + params.primaryControllerFlags[Rig::PrimaryControllerType_Head] = (uint8_t)Rig::ControllerFlags::Enabled; } else { // even though full head IK is disabled, the rig still needs the head orientation to rotate the head up and // down in desktop mode. @@ -114,7 +114,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { // postMult 180 is necessary to convert head from -z forward to z forward. glm::quat headRot = Quaternions::Y_180 * head->getFinalOrientationInLocalFrame() * Quaternions::Y_180; params.primaryControllerPoses[Rig::PrimaryControllerType_Head] = AnimPose(glm::vec3(1.0f), headRot, glm::vec3(0.0f)); - params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Head] = false; + params.primaryControllerFlags[Rig::PrimaryControllerType_Head] = 0; } // @@ -135,10 +135,10 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { if (controllerPose.isValid()) { AnimPose pose(controllerPose.getRotation(), controllerPose.getTranslation()); params.primaryControllerPoses[pair.second] = avatarToRigPose * pose; - params.primaryControllerActiveFlags[pair.second] = true; + params.primaryControllerFlags[pair.second] = (uint8_t)Rig::ControllerFlags::Enabled; } else { params.primaryControllerPoses[pair.second] = AnimPose::identity; - params.primaryControllerActiveFlags[pair.second] = false; + params.primaryControllerFlags[pair.second] = 0; } } @@ -166,15 +166,15 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { if (controllerPose.isValid()) { AnimPose pose(controllerPose.getRotation(), controllerPose.getTranslation()); params.secondaryControllerPoses[pair.second] = avatarToRigPose * pose; - params.secondaryControllerActiveFlags[pair.second] = true; + params.secondaryControllerFlags[pair.second] = (uint8_t)Rig::ControllerFlags::Enabled; } else { params.secondaryControllerPoses[pair.second] = AnimPose::identity; - params.secondaryControllerActiveFlags[pair.second] = false; + params.secondaryControllerFlags[pair.second] = 0; } } // if hips are not under direct control, estimate the hips position. - if (avatarHeadPose.isValid() && !params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Hips]) { + if (avatarHeadPose.isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] & (uint8_t)Rig::ControllerFlags::Enabled)) { bool isFlying = (myAvatar->getCharacterController()->getState() == CharacterController::State::Hover || myAvatar->getCharacterController()->computeCollisionGroup() == BULLET_COLLISION_GROUP_COLLISIONLESS); if (!_prevHipsValid) { @@ -200,7 +200,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { AnimPose sensorToRigPose(invRigMat * myAvatar->getSensorToWorldMatrix()); params.primaryControllerPoses[Rig::PrimaryControllerType_Hips] = sensorToRigPose * hips; - params.primaryControllerActiveFlags[Rig::PrimaryControllerType_Hips] = true; + params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; } else { _prevHipsValid = false; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 44745c5c2d..27ba7a38a4 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1265,7 +1265,8 @@ glm::vec3 Rig::deflectHandFromTorso(const glm::vec3& handPosition, const FBXJoin return position; } -void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool leftArmEnabled, bool rightArmEnabled, float dt, +void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated, + bool leftArmEnabled, bool rightArmEnabled, float dt, const AnimPose& leftHandPose, const AnimPose& rightHandPose, const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo, const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo) { @@ -1279,7 +1280,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab glm::vec3 handPosition = leftHandPose.trans(); glm::quat handRotation = leftHandPose.rot(); - if (!hipsEnabled) { + if (!hipsEnabled || hipsEstimated) { // prevent the hand IK targets from intersecting the torso handPosition = deflectHandFromTorso(handPosition, hipsShapeInfo, spineShapeInfo, spine1ShapeInfo, spine2ShapeInfo); } @@ -1326,7 +1327,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab glm::vec3 handPosition = rightHandPose.trans(); glm::quat handRotation = rightHandPose.rot(); - if (!hipsEnabled) { + if (!hipsEnabled || hipsEstimated) { // prevent the hand IK targets from intersecting the torso handPosition = deflectHandFromTorso(handPosition, hipsShapeInfo, spineShapeInfo, spine1ShapeInfo, spine2ShapeInfo); } @@ -1550,20 +1551,20 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo _animVars.set("isTalking", params.isTalking); _animVars.set("notIsTalking", !params.isTalking); - bool headEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_Head]; - bool leftHandEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_LeftHand]; - bool rightHandEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_RightHand]; - bool hipsEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_Hips]; - bool leftFootEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_LeftFoot]; - bool rightFootEnabled = params.primaryControllerActiveFlags[PrimaryControllerType_RightFoot]; - bool spine2Enabled = params.primaryControllerActiveFlags[PrimaryControllerType_Spine2]; - - bool leftArmEnabled = params.secondaryControllerActiveFlags[SecondaryControllerType_LeftArm]; - bool rightArmEnabled = params.secondaryControllerActiveFlags[SecondaryControllerType_RightArm]; + bool headEnabled = params.primaryControllerFlags[PrimaryControllerType_Head] & (uint8_t)ControllerFlags::Enabled; + bool leftHandEnabled = params.primaryControllerFlags[PrimaryControllerType_LeftHand] & (uint8_t)ControllerFlags::Enabled; + bool rightHandEnabled = params.primaryControllerFlags[PrimaryControllerType_RightHand] & (uint8_t)ControllerFlags::Enabled; + bool hipsEnabled = params.primaryControllerFlags[PrimaryControllerType_Hips] & (uint8_t)ControllerFlags::Enabled; + bool hipsEstimated = params.primaryControllerFlags[PrimaryControllerType_Hips] & (uint8_t)ControllerFlags::Estimated; + bool leftFootEnabled = params.primaryControllerFlags[PrimaryControllerType_LeftFoot] & (uint8_t)ControllerFlags::Enabled; + bool rightFootEnabled = params.primaryControllerFlags[PrimaryControllerType_RightFoot] & (uint8_t)ControllerFlags::Enabled; + bool spine2Enabled = params.primaryControllerFlags[PrimaryControllerType_Spine2] & (uint8_t)ControllerFlags::Enabled; + bool leftArmEnabled = params.secondaryControllerFlags[SecondaryControllerType_LeftArm] & (uint8_t)ControllerFlags::Enabled; + bool rightArmEnabled = params.secondaryControllerFlags[SecondaryControllerType_RightArm] & (uint8_t)ControllerFlags::Enabled; updateHead(headEnabled, hipsEnabled, params.primaryControllerPoses[PrimaryControllerType_Head]); - updateHands(leftHandEnabled, rightHandEnabled, hipsEnabled, leftArmEnabled, rightArmEnabled, dt, + updateHands(leftHandEnabled, rightHandEnabled, hipsEnabled, hipsEstimated, leftArmEnabled, rightArmEnabled, dt, params.primaryControllerPoses[PrimaryControllerType_LeftHand], params.primaryControllerPoses[PrimaryControllerType_RightHand], params.hipsShapeInfo, params.spineShapeInfo, params.spine1ShapeInfo, params.spine2ShapeInfo); @@ -1623,7 +1624,7 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo for (int i = 0; i < (int)NumSecondaryControllerTypes; i++) { int index = indexOfJoint(secondaryControllerJointNames[i]); if (index >= 0) { - if (params.secondaryControllerActiveFlags[i]) { + if (params.secondaryControllerFlags[i] & (uint8_t)ControllerFlags::Enabled) { ikNode->setSecondaryTargetInRigFrame(index, params.secondaryControllerPoses[i]); } else { ikNode->clearSecondaryTarget(index); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 1ec4d9527f..2b276386a0 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -69,11 +69,16 @@ public: NumSecondaryControllerTypes }; + enum class ControllerFlags : uint8_t { + Enabled = 0x01, + Estimated = 0x02 + }; + struct ControllerParameters { AnimPose primaryControllerPoses[NumPrimaryControllerTypes]; // rig space - bool primaryControllerActiveFlags[NumPrimaryControllerTypes]; + uint8_t primaryControllerFlags[NumPrimaryControllerTypes]; AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space - bool secondaryControllerActiveFlags[NumSecondaryControllerTypes]; + uint8_t secondaryControllerFlags[NumSecondaryControllerTypes]; bool isTalking; FBXJointShapeInfo hipsShapeInfo; FBXJointShapeInfo spineShapeInfo; @@ -251,7 +256,8 @@ protected: void buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut); void updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headMatrix); - void updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool leftArmEnabled, bool rightArmEnabled, float dt, + void updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated, + bool leftArmEnabled, bool rightArmEnabled, float dt, const AnimPose& leftHandPose, const AnimPose& rightHandPose, const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo, const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo); From b26e31a36244579a41516b79d84754ea122c34fd Mon Sep 17 00:00:00 2001 From: Cain Kilgore Date: Wed, 10 Jan 2018 20:27:19 +0000 Subject: [PATCH 12/13] Copy paste? Never! --- interface/src/scripting/WindowScriptingInterface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 3b8412900f..33ff8d1f96 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -1,5 +1,5 @@ // -// WindowScriptingInterface.cpp +// WindowScriptingInterface.h // interface/src/scripting // // Created by Ryan Huffman on 4/29/14. From 104ac0ffae379d48f70b1e6827f341b83ae9177e Mon Sep 17 00:00:00 2001 From: Cain Kilgore Date: Wed, 10 Jan 2018 20:30:41 +0000 Subject: [PATCH 13/13] Indents, man --- interface/resources/qml/dialogs/FileDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index d2115b5e7e..7b1a177c86 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -636,7 +636,7 @@ ModalWindow { case Qt.Key_Backtab: event.accepted = false; break; - case Qt.Key_Escape: + case Qt.Key_Escape: event.accepted = true; root.click(OriginalDialogs.StandardButton.Cancel); break;