From 0c6f5bb04d525c7649469517492835a05bcf959a Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 26 Mar 2018 10:51:25 -0700 Subject: [PATCH 01/20] adding python baking scripts --- tools/bake-tools/bake.py | 91 ++++++++++++++++++++++ tools/bake-tools/convertToRelativePaths.py | 82 +++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100644 tools/bake-tools/bake.py create mode 100644 tools/bake-tools/convertToRelativePaths.py diff --git a/tools/bake-tools/bake.py b/tools/bake-tools/bake.py new file mode 100644 index 0000000000..0c8d5e1048 --- /dev/null +++ b/tools/bake-tools/bake.py @@ -0,0 +1,91 @@ +import os, json, sys, shutil, subprocess, shlex, time +EXE = os.environ['HIFI_OVEN'] + +def listFiles(directory, extension): + items = os.listdir(directory) + fileList = [] + for f in items: + if f.endswith('.' + extension): + fileList.append(f) + return fileList + +def camelCaseString(string): + string = string.replace('-', ' ') + return ''.join(x for x in string.title() if not x.isspace()) + +def groupFiles(originalDirectory, newDirectory, files): + for file in files: + newPath = os.sep.join([newDirectory, file]) + originalPath = os.sep.join([originalDirectory, file]) + shutil.move(originalPath, newPath) + +def groupKTXFiles(directory, filePath): + baseFile = os.path.basename(filePath) + filename = os.path.splitext(baseFile)[0] + camelCaseFileName = camelCaseString(filename) + path = os.sep.join([directory, camelCaseFileName]) + files = listFiles(directory, 'ktx') + if len(files) > 0: + createDirectory(path) + groupFiles(directory, path, files) + + newFilePath = os.sep.join([path, baseFile+'.baked.fbx']) + originalFilePath = os.sep.join([directory, baseFile+'.baked.fbx']) + originalFilePath.strip() + shutil.move(originalFilePath, newFilePath) + +def bakeFile(filePath, outputDirectory): + createDirectory(outputDirectory) + cmd = EXE + ' -i ' + filePath + ' -o ' + outputDirectory + ' -t fbx' + args = shlex.split(cmd) + process = subprocess.Popen(cmd, stdout=False, stderr=False) + process.wait() + bakedFile = os.path.splitext(filePath)[0] + groupKTXFiles(outputDirectory, bakedFile) + +def bakeFilesInDirectory(directory, outputDirectory): + for root, subFolders, filenames in os.walk(directory): + for filename in filenames: + if filename.endswith('.fbx'): + filePath = os.sep.join([root, filename]) + absFilePath = os.path.abspath(filePath) + outputFolder = os.path.join(outputDirectory, os.path.relpath(root)) + print "Baking file: " + filename + bakeFile(absFilePath, outputFolder) + else: + filePath = os.sep.join([root, filename]) + absFilePath = os.path.abspath(filePath) + outputFolder = os.path.join(outputDirectory, os.path.relpath(root)) + newFilePath = os.sep.join([outputFolder, filename]) + createDirectory(outputFolder) + print "moving file: " + filename + " to: " + outputFolder + shutil.copy(absFilePath, newFilePath) + +def createDirectory(directory): + if not os.path.exists(directory): + os.makedirs(directory) + +def checkIfExeExists(): + if not os.path.isfile(EXE) and os.access(EXE, os.X_OK): + print 'HIFI_OVEN evironment variable is not set' + sys.exit() + +def handleOptions(): + option = sys.argv[1] + if option == '--help' or option == '-h': + print 'Usage: bake.py INPUT_DIRECTORY[directory to bake] OUTPUT_DIRECTORY[directory to place backed files]' + print 'Note: Output directory will be created if directory does not exist' + sys.exit() + +def main(): + argsLength = len(sys.argv) + if argsLength == 3: + checkIfExeExists() + rootDirectory = sys.argv[1] + outputDirectory = os.path.abspath(sys.argv[2]) + createDirectory(outputDirectory) + bakeFilesInDirectory(rootDirectory, outputDirectory) + elif argsLength == 2: + handleOptions() + +main() diff --git a/tools/bake-tools/convertToRelativePaths.py b/tools/bake-tools/convertToRelativePaths.py new file mode 100644 index 0000000000..27a7b7ac02 --- /dev/null +++ b/tools/bake-tools/convertToRelativePaths.py @@ -0,0 +1,82 @@ +import json, os, sys, gzip + +prefix = 'file:///~/' +MAP = {} +def createAssetMapping(assetDirectory): + baseDirectory = os.path.basename(os.path.normpath(assetDirectory)) + for root, subfolder, filenames in os.walk(assetDirectory): + for filename in filenames: + if not filename.endswith('.ktx'): + substring = os.path.commonprefix([assetDirectory, root]) + newPath = root.replace(substring, ''); + filePath = os.sep.join([newPath, filename]) + if filePath[0] == '\\': + filePath = filePath[1:] + finalPath = prefix + baseDirectory + '/' + filePath + finalPath = finalPath.replace('\\', '/') + file = os.path.splitext(filename)[0] + file = os.path.splitext(file)[0] + MAP[file] = finalPath + +def hasURL(prop): + if "URL" in prop: + return True + return False + + +def handleURL(url): + newUrl = url + if "atp:" in url: + baseFilename = os.path.basename(url) + filename = os.path.splitext(baseFilename)[0] + newUrl = MAP[filename] + print newUrl + return newUrl + +def handleOptions(): + option = sys.argv[1] + if option == '--help' or option == '-h': + print 'Usage: convertToRelativePaths.py INPUT[json file you want to update the urls] INPUT[directory that the baked files are located in]' + sys.exit() + +def main(): + argsLength = len(sys.argv) + if argsLength == 3: + jsonFile = sys.argv[1] + gzipFile = jsonFile + '.gz' + assetDirectory = sys.argv[2] + createAssetMapping(assetDirectory) + f = open(jsonFile) + data = json.load(f) + f.close() + for entity in data['Entities']: + for prop in entity: + value = entity[prop] + if hasURL(prop): + value = handleURL(value) + if prop == "script": + value = handleURL(value) + if prop == "textures": + try: + tmp = json.loads(value) + for index in tmp: + tmp[index] = handleURL(tmp[index]) + value = json.dumps(tmp) + except: + value = handleURL(value) + + if prop == "serverScripts": + value = handleURL(value) + + entity[prop] = value + + + jsonString = json.dumps(data) + jsonBytes= jsonString.encode('utf-8') + with gzip.GzipFile(gzipFile, 'w') as fout: # 4. gzip + fout.write(jsonBytes) + + elif argsLength == 2: + handleOptions() + +main() From cb07fc47dc58e86c4982105a04e02e721dfb60db Mon Sep 17 00:00:00 2001 From: Clement Date: Tue, 27 Mar 2018 13:27:02 -0700 Subject: [PATCH 02/20] Fix ESS remote method calls for connect only users --- .../src/scripts/EntityScriptServer.cpp | 9 +---- domain-server/src/DomainServer.cpp | 38 +------------------ 2 files changed, 4 insertions(+), 43 deletions(-) diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 1255c18e71..d242b393bf 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -105,8 +105,6 @@ EntityScriptServer::~EntityScriptServer() { static const QString ENTITY_SCRIPT_SERVER_LOGGING_NAME = "entity-script-server"; void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode) { - // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them - // about each other. if (senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified()) { auto entityID = QUuid::fromRfc4122(message->read(NUM_BYTES_RFC4122_UUID)); @@ -119,8 +117,6 @@ void EntityScriptServer::handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode) { - // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them - // about each other. if (senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified()) { MessageID messageID; message->readPrimitive(&messageID); @@ -190,15 +186,14 @@ void EntityScriptServer::updateEntityPPS() { } void EntityScriptServer::handleEntityServerScriptLogPacket(QSharedPointer message, SharedNodePointer senderNode) { - // These are temporary checks until we can ensure that nodes eventually disconnect if the Domain Server stops telling them - // about each other. + bool canRezAny = senderNode->getCanRez() || senderNode->getCanRezTmp() || senderNode->getCanRezCertified() || senderNode->getCanRezTmpCertified(); bool enable = false; message->readPrimitive(&enable); auto senderUUID = senderNode->getUUID(); auto it = _logListeners.find(senderUUID); - if (enable && senderNode->getCanRez()) { + if (enable && canRezAny) { if (it == std::end(_logListeners)) { _logListeners.insert(senderUUID); qCInfo(entity_script_server) << "Node" << senderUUID << "subscribed to log stream"; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 197ac7eac2..dbf2907cc0 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1042,41 +1042,7 @@ void DomainServer::processListRequestPacket(QSharedPointer mess bool DomainServer::isInInterestSet(const SharedNodePointer& nodeA, const SharedNodePointer& nodeB) { auto nodeAData = static_cast(nodeA->getLinkedData()); - auto nodeBData = static_cast(nodeB->getLinkedData()); - - // if we have no linked data for node A then B can't possibly be in the interest set - if (!nodeAData) { - return false; - } - - // first check if the general interest set A contains the type for B - if (nodeAData->getNodeInterestSet().contains(nodeB->getType())) { - // given that there is a match in the general interest set, do any special checks - - // (1/19/17) Agents only need to connect to Entity Script Servers to perform administrative tasks - // related to entity server scripts. Only agents with rez permissions should be doing that, so - // if the agent does not have those permissions, we do not want them and the server to incur the - // overhead of connecting to one another. Additionally we exclude agents that do not care about the - // Entity Script Server and won't attempt to connect to it. - - bool isAgentWithoutRights = nodeA->getType() == NodeType::Agent - && nodeB->getType() == NodeType::EntityScriptServer - && !nodeA->getCanRez() && !nodeA->getCanRezTmp() - && !nodeA->getCanRezCertified() && !nodeA->getCanRezTmpCertified(); - - if (isAgentWithoutRights) { - return false; - } - - bool isScriptServerForIneffectiveAgent = - (nodeA->getType() == NodeType::EntityScriptServer && nodeB->getType() == NodeType::Agent) - && ((nodeBData && !nodeBData->getNodeInterestSet().contains(NodeType::EntityScriptServer)) - || (!nodeB->getCanRez() && !nodeB->getCanRezTmp() && !nodeB->getCanRezCertified() && !nodeB->getCanRezTmpCertified())); - - return !isScriptServerForIneffectiveAgent; - } else { - return false; - } + return nodeAData && nodeAData->getNodeInterestSet().contains(nodeB->getType()); } unsigned int DomainServer::countConnectedUsers() { @@ -3476,4 +3442,4 @@ void DomainServer::handleOctreeFileReplacementRequest(QSharedPointergetCanReplaceContent()) { handleOctreeFileReplacement(message->readAll()); } -} \ No newline at end of file +} From ca3fe28b05f80801bdf96abb97d83fcacb60b6dc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 27 Mar 2018 18:51:44 -0700 Subject: [PATCH 03/20] JavaScript exceptions during Controller system callbacks are now logged (cherry picked from commit d3aec12e9e76e4aeb8ecbd449cc76afda1a0e35d) --- .../controllers/impl/endpoints/JSEndpoint.cpp | 47 ++++++++++++++++--- .../controllers/impl/endpoints/JSEndpoint.h | 11 ++--- .../impl/endpoints/ScriptEndpoint.cpp | 45 +++++++++++++++--- 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp index 7f0e80cbae..2f20cd82c6 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.cpp @@ -6,10 +6,43 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// NOTE: we don't need to include this header unless/until we add additional symbols. -// By removing this header we prevent these warnings on windows: -// -// warning LNK4221: This object file does not define any previously undefined public symbols, -// so it will not be used by any link operation that consumes this library -// -//#include "JSEndpoint.h" \ No newline at end of file +#include "JSEndpoint.h" +#include "../../Logging.h" + +using namespace controller; + +QString formatException(const QJSValue& exception) { + QString note { "UncaughtException" }; + QString result; + + const auto message = exception.toString(); + const auto fileName = exception.property("fileName").toString(); + const auto lineNumber = exception.property("lineNumber").toString(); + const auto stacktrace = exception.property("stack").toString(); + + const QString SCRIPT_EXCEPTION_FORMAT = "[%0] %1 in %2:%3"; + const QString SCRIPT_BACKTRACE_SEP = "\n "; + + result = QString(SCRIPT_EXCEPTION_FORMAT).arg(note, message, fileName, lineNumber); + if (!stacktrace.isEmpty()) { + result += QString("\n[Backtrace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace); + } + return result; +} + +float JSEndpoint::peek() const { + QJSValue result = _callable.call(); + if (result.isError()) { + qCDebug(controllers).noquote() << formatException(result); + return 0.0f; + } else { + return (float)result.toNumber(); + } +} + +void JSEndpoint::apply(float newValue, const Pointer& source) { + QJSValue result = _callable.call(QJSValueList({ QJSValue(newValue) })); + if (result.isError()) { + qCDebug(controllers).noquote() << formatException(result); + } +} diff --git a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h index 24d5ec93e9..4d179da8e6 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/JSEndpoint.h @@ -24,16 +24,11 @@ public: : Endpoint(Input::INVALID_INPUT), _callable(callable) { } - virtual float peek() const override { - return (float)const_cast(this)->_callable.call().toNumber(); - } - - virtual void apply(float newValue, const Pointer& source) override { - _callable.call(QJSValueList({ QJSValue(newValue) })); - } + virtual float peek() const override; + virtual void apply(float newValue, const Pointer& source) override; private: - QJSValue _callable; + mutable QJSValue _callable; }; } diff --git a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp index 3e7fde347e..e2c48d776f 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp +++ b/libraries/controllers/src/controllers/impl/endpoints/ScriptEndpoint.cpp @@ -7,6 +7,7 @@ // #include "ScriptEndpoint.h" +#include "../../Logging.h" #include @@ -14,6 +15,25 @@ using namespace controller; +QString formatException(const QScriptValue& exception) { + QString note { "UncaughtException" }; + QString result; + + const auto message = exception.toString(); + const auto fileName = exception.property("fileName").toString(); + const auto lineNumber = exception.property("lineNumber").toString(); + const auto stacktrace = exception.property("stack").toString(); + + const QString SCRIPT_EXCEPTION_FORMAT = "[%0] %1 in %2:%3"; + const QString SCRIPT_BACKTRACE_SEP = "\n "; + + result = QString(SCRIPT_EXCEPTION_FORMAT).arg(note, message, fileName, lineNumber); + if (!stacktrace.isEmpty()) { + result += QString("\n[Backtrace]%1%2").arg(SCRIPT_BACKTRACE_SEP).arg(stacktrace); + } + return result; +} + float ScriptEndpoint::peek() const { const_cast(this)->updateValue(); return _lastValueRead; @@ -26,10 +46,11 @@ void ScriptEndpoint::updateValue() { } QScriptValue result = _callable.call(); - - // If the callable ever returns a non-number, we assume it's a pose - // and start reporting ourselves as a pose. - if (result.isNumber()) { + if (result.isError()) { + // print JavaScript exception + qCDebug(controllers).noquote() << formatException(result); + _lastValueRead = 0.0f; + } else if (result.isNumber()) { _lastValueRead = (float)_callable.call().toNumber(); } else { Pose::fromScriptValue(result, _lastPoseRead); @@ -52,8 +73,12 @@ void ScriptEndpoint::internalApply(float value, int sourceID) { Q_ARG(int, sourceID)); return; } - _callable.call(QScriptValue(), + QScriptValue result = _callable.call(QScriptValue(), QScriptValueList({ QScriptValue(value), QScriptValue(sourceID) })); + if (result.isError()) { + // print JavaScript exception + qCDebug(controllers).noquote() << formatException(result); + } } Pose ScriptEndpoint::peekPose() const { @@ -67,6 +92,10 @@ void ScriptEndpoint::updatePose() { return; } QScriptValue result = _callable.call(); + if (result.isError()) { + // print JavaScript exception + qCDebug(controllers).noquote() << formatException(result); + } Pose::fromScriptValue(result, _lastPoseRead); } @@ -85,6 +114,10 @@ void ScriptEndpoint::internalApply(const Pose& newPose, int sourceID) { Q_ARG(int, sourceID)); return; } - _callable.call(QScriptValue(), + QScriptValue result = _callable.call(QScriptValue(), QScriptValueList({ Pose::toScriptValue(_callable.engine(), newPose), QScriptValue(sourceID) })); + if (result.isError()) { + // print JavaScript exception + qCDebug(controllers).noquote() << formatException(result); + } } From 35ee1bec09963cc27135512eaa2a82a085fd295d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 28 Mar 2018 14:47:09 -0700 Subject: [PATCH 04/20] fix cmake changes for script copy for dev builds --- interface/CMakeLists.txt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index e316556d29..fe00d86c3a 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -312,7 +312,7 @@ if (APPLE) COMPONENT ${CLIENT_COMPONENT} ) - set(RESOURCES_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources") + set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_APP_PATH}/Contents/Resources") set(RESOURCES_DEV_DIR "$/../Resources") # copy script files beside the executable @@ -326,13 +326,14 @@ if (APPLE) fixup_interface() else() - set(RESOURCES_DEV_DIR "$/resources") + set(INTERFACE_EXEC_DIR "$") + set(RESOURCES_DEV_DIR "${INTERFACE_EXEC_DIR}/resources") # copy the resources files beside the executable add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${RESOURCES_RCC}" - "$" + "${INTERFACE_EXEC_DIR}" # FIXME, the edit script code loads HTML from the scripts folder # which in turn relies on CSS that refers to the fonts. In theory # we should be able to modify the CSS to reference the QRC path to @@ -340,13 +341,13 @@ else() # so we have to retain a copy of the fonts outside of the resources binary COMMAND "${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/resources/fonts" - "$/resources/fonts" + "${RESOURCES_DEV_DIR}/fonts" COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/scripts" - "${RESOURCES_DEV_DIR}/scripts" + "${INTERFACE_EXEC_DIR}/scripts" COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json" - "$/resources/serverless/tutorial.json" + "${RESOURCES_DEV_DIR}/serverless/tutorial.json" ) # link target to external libraries @@ -363,7 +364,7 @@ else() PATTERN "*.exp" EXCLUDE ) - set(RESOURCES_INSTALL_DIR "${INTERFACE_INSTALL_DIR}") + set(SCRIPTS_INSTALL_DIR "${INTERFACE_INSTALL_DIR}") set(EXECUTABLE_COMPONENT ${CLIENT_COMPONENT}) @@ -371,11 +372,11 @@ else() endif() endif() -if (RESOURCES_INSTALL_DIR) +if (SCRIPTS_INSTALL_DIR) # setup install of scripts beside interface executable install( DIRECTORY "${CMAKE_SOURCE_DIR}/scripts/" - DESTINATION ${RESOURCES_INSTALL_DIR}/scripts + DESTINATION ${SCRIPTS_INSTALL_DIR}/scripts COMPONENT ${CLIENT_COMPONENT} ) endif() From 8cdb59413d7c3ad06d90a082239261756990ecf5 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 09:26:05 -0700 Subject: [PATCH 05/20] fix-qml-confict --- interface/resources/qml/{AudioScope.qml => AudioScopeUI.qml} | 1 + scripts/developer/utilities/audio/audioScope.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) rename interface/resources/qml/{AudioScope.qml => AudioScopeUI.qml} (99%) diff --git a/interface/resources/qml/AudioScope.qml b/interface/resources/qml/AudioScopeUI.qml similarity index 99% rename from interface/resources/qml/AudioScope.qml rename to interface/resources/qml/AudioScopeUI.qml index aa181dbf8d..b009c249bc 100644 --- a/interface/resources/qml/AudioScope.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -12,6 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "styles-uit" import "controls-uit" as HifiControlsUit +import "." as HifiRoot Item { id: root diff --git a/scripts/developer/utilities/audio/audioScope.js b/scripts/developer/utilities/audio/audioScope.js index 00c9e4b725..63cbf0a6e2 100644 --- a/scripts/developer/utilities/audio/audioScope.js +++ b/scripts/developer/utilities/audio/audioScope.js @@ -1,4 +1,4 @@ -var qml = Script.resourcesPath() + '/qml/AudioScope.qml'; +var qml = Script.resourcesPath() + '/qml/AudioScopeUI.qml'; var window = new OverlayWindow({ title: 'Audio Scope', source: qml, @@ -14,4 +14,4 @@ window.closed.connect(function () { AudioScope.setServerEcho(false); AudioScope.selectAudioScopeFiveFrames(); Script.stop(); -}); \ No newline at end of file +}); From 0bdf26faaf321d09d9501830862aafd778d7adcc Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 29 Mar 2018 09:29:01 -0700 Subject: [PATCH 06/20] minimize diff --- interface/resources/qml/AudioScopeUI.qml | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/resources/qml/AudioScopeUI.qml b/interface/resources/qml/AudioScopeUI.qml index b009c249bc..aa181dbf8d 100644 --- a/interface/resources/qml/AudioScopeUI.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -12,7 +12,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "styles-uit" import "controls-uit" as HifiControlsUit -import "." as HifiRoot Item { id: root From afe39aba46b9c69e3ba6a4c6981f8f8da37c5ac1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 28 Mar 2018 13:47:31 -0700 Subject: [PATCH 07/20] fix octal code char issue --- libraries/entities/src/EntityTree.cpp | 6 +++--- libraries/entities/src/UpdateEntityOperator.cpp | 2 +- libraries/shared/src/OctalCode.cpp | 6 +++--- libraries/shared/src/OctalCode.h | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 75f024d0b9..2cf66911a4 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -425,8 +425,8 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti if (!childEntity) { continue; } - EntityTreeElementPointer containingElement = childEntity->getElement(); - if (!containingElement) { + EntityTreeElementPointer childContainingElement = childEntity->getElement(); + if (!childContainingElement) { continue; } @@ -440,7 +440,7 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti addToNeedsParentFixupList(childEntity); } - UpdateEntityOperator theChildOperator(getThisPointer(), containingElement, childEntity, queryCube); + UpdateEntityOperator theChildOperator(getThisPointer(), childContainingElement, childEntity, queryCube); recurseTreeWithOperator(&theChildOperator); foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) { if (childChild && childChild->getNestableType() == NestableType::Entity) { diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index fa7e5ca38f..32bd2f06ba 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -288,7 +288,7 @@ OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(const OctreeEle int indexOfChildContainingNewEntity = element->getMyChildContaining(_newEntityBox); if (childIndex == indexOfChildContainingNewEntity) { - return element->addChildAtIndex(childIndex);; + return element->addChildAtIndex(childIndex); } } } diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 1a0a19bf44..ae4338be6f 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -46,7 +46,7 @@ void printOctalCode(const unsigned char* octalCode) { } char sectionValue(const unsigned char* startByte, char startIndexInByte) { - char rightShift = 8 - startIndexInByte - 3; + int8_t rightShift = 8 - startIndexInByte - 3; if (rightShift < 0) { return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift)); @@ -73,7 +73,7 @@ int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsi return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8); } -unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) { +unsigned char* childOctalCode(const unsigned char* parentOctalCode, int childNumber) { // find the length (in number of three bit code sequences) // in the parent @@ -111,7 +111,7 @@ unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNu // calculate the amount of left shift required // this will be -1 or -2 if there's wrap - char leftShift = 8 - (startBit % 8) - 3; + int8_t leftShift = 8 - (startBit % 8) - 3; if (leftShift < 0) { // we have a wrap-around to accomodate diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index a0d86f32d2..89c5e6d74e 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -30,7 +30,7 @@ using OctalCodePtrList = std::vector; void printOctalCode(const unsigned char* octalCode); size_t bytesRequiredForCodeLength(unsigned char threeBitCodes); int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode); -unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber); +unsigned char* childOctalCode(const unsigned char* parentOctalCode, int childNumber); const int OVERFLOWED_OCTCODE_BUFFER = -1; const int UNKNOWN_OCTCODE_LENGTH = -2; From dcfebde54a7ea2f66b2abd1f2abb5ac205b9dfe5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 29 Mar 2018 10:50:43 -0700 Subject: [PATCH 08/20] put back the pre serverless-domain behavior for when a json file is dragged-and-dropped into the interface window -- import the json rather than load as a serverless-domain --- interface/src/Application.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7e6c65f8f4..af0ac5bc78 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6275,8 +6275,9 @@ bool Application::canAcceptURL(const QString& urlString) const { bool Application::acceptURL(const QString& urlString, bool defaultUpload) { QUrl url(urlString); - if (isDomainURL(url)) { - // this is a URL for a domain, either hifi:// or serverless - have the AddressManager handle it + + if (url.scheme() == URL_SCHEME_HIFI) { + // this is a hifi URL - have the AddressManager handle it QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString", Qt::AutoConnection, Q_ARG(const QString&, urlString)); return true; From 3b9007809793ebcd2437fc231fa27fdf0666e867 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 30 Mar 2018 08:36:18 +1300 Subject: [PATCH 09/20] Remove Entities.currentAvatarEnergy and related from the API --- .../entities/src/EntityScriptingInterface.cpp | 59 +------------------ .../entities/src/EntityScriptingInterface.h | 18 ------ 2 files changed, 2 insertions(+), 75 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 7e15e78624..c4a9956c90 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -258,12 +258,6 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties float volume = dimensions.x * dimensions.y * dimensions.z; auto density = propertiesWithSimID.getDensity(); auto newVelocity = propertiesWithSimID.getVelocity().length(); - float cost = calculateCost(density * volume, 0, newVelocity); - cost *= costMultiplier; - - if (cost > _currentAvatarEnergy) { - return QUuid(); - } EntityItemID id = EntityItemID(QUuid::createUuid()); @@ -295,9 +289,7 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties // queue the packet if (success) { - emit debitEnergySource(cost); queueEntityMessage(PacketType::EntityAdd, id, propertiesWithSimID); - return id; } else { return QUuid(); @@ -387,18 +379,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& EntityItemID entityID(id); if (!_entityTree) { queueEntityMessage(PacketType::EntityEdit, entityID, properties); - - //if there is no local entity entity tree, no existing velocity, use 0. - float cost = calculateCost(density * volume, oldVelocity, newVelocity); - cost *= costMultiplier; - - if (cost > _currentAvatarEnergy) { - return QUuid(); - } else { - //debit the avatar energy and continue - emit debitEnergySource(cost); - } - return id; } // If we have a local entity tree set, then also update it. @@ -442,23 +422,11 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties.setClientOnly(entity->getClientOnly()); properties.setOwningAvatarID(entity->getOwningAvatarID()); properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent()); - - float cost = calculateCost(density * volume, oldVelocity, newVelocity); - cost *= costMultiplier; - - if (cost > _currentAvatarEnergy) { - updatedEntity = false; - } else { - //debit the avatar energy and continue - updatedEntity = _entityTree->updateEntity(entityID, properties); - if (updatedEntity) { - emit debitEnergySource(cost); - } - } + updatedEntity = _entityTree->updateEntity(entityID, properties); }); // FIXME: We need to figure out a better way to handle this. Allowing these edits to go through potentially - // breaks avatar energy and entities that are parented. + // breaks entities that are parented. // // To handle cases where a script needs to edit an entity with a _known_ entity id but doesn't exist // in the local entity tree, we need to allow those edits to go through to the server. @@ -581,16 +549,6 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { float volume = dimensions.x * dimensions.y * dimensions.z; auto density = entity->getDensity(); auto velocity = entity->getWorldVelocity().length(); - float cost = calculateCost(density * volume, velocity, 0); - cost *= costMultiplier; - - if (cost > _currentAvatarEnergy) { - shouldDelete = false; - return; - } else { - //debit the avatar energy and continue - emit debitEnergySource(cost); - } if (entity->getLocked()) { shouldDelete = false; @@ -1816,19 +1774,6 @@ float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, flo return std::abs(mass * (newVelocity - oldVelocity)); } -void EntityScriptingInterface::setCurrentAvatarEnergy(float energy) { - // qCDebug(entities) << "NEW AVATAR ENERGY IN ENTITY SCRIPTING INTERFACE: " << energy; - _currentAvatarEnergy = energy; -} - -float EntityScriptingInterface::getCostMultiplier() { - return costMultiplier; -} - -void EntityScriptingInterface::setCostMultiplier(float value) { - costMultiplier = value; -} - // TODO move this someplace that makes more sense... bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, const glm::vec3& start, const glm::vec3& end, float radius) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 9613a7a310..f92a88e0d2 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -94,8 +94,6 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra * Interface has displayed and so knows about. * * @namespace Entities - * @property {number} currentAvatarEnergy - Deprecated - * @property {number} costMultiplier - Deprecated * @property {Uuid} keyboardFocusEntity - Get or set the {@link Entities.EntityType|Web} entity that has keyboard focus. * If no entity has keyboard focus, get returns null; set to null or {@link Uuid|Uuid.NULL} to * clear keyboard focus. @@ -104,8 +102,6 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra class EntityScriptingInterface : public OctreeScriptingInterface, public Dependency { Q_OBJECT - Q_PROPERTY(float currentAvatarEnergy READ getCurrentAvatarEnergy WRITE setCurrentAvatarEnergy) - Q_PROPERTY(float costMultiplier READ getCostMultiplier WRITE setCostMultiplier) Q_PROPERTY(QUuid keyboardFocusEntity READ getKeyboardFocusEntity WRITE setKeyboardFocusEntity) friend EntityPropertyMetadataRequest; @@ -1834,14 +1830,6 @@ signals: */ void clearingEntities(); - /**jsdoc - * @function Entities.debitEnergySource - * @param {number} value - The amount to debit. - * @returns {Signal} - * @deprecated This function is deprecated and will soon be removed. - */ - void debitEnergySource(float value); - /**jsdoc * Triggered in when a script in a {@link Entities.EntityType|Web} entity's Web page script sends an event over the * script's EventBridge. @@ -1882,14 +1870,8 @@ private: QSharedPointer _entitiesScriptEngine; bool _bidOnSimulationOwnership { false }; - float _currentAvatarEnergy = { FLT_MAX }; - float getCurrentAvatarEnergy() { return _currentAvatarEnergy; } - void setCurrentAvatarEnergy(float energy); ActivityTracking _activityTracking; - float costMultiplier = { 0.01f }; - float getCostMultiplier(); - void setCostMultiplier(float value); }; #endif // hifi_EntityScriptingInterface_h From e5da59a62f53e15bae36d524e208f249f6723719 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 16 Mar 2018 15:54:42 +0300 Subject: [PATCH 10/20] FB12870 - Tablet UI ->Asset Browser unresponsive when enabling/disabling "use baked version" --- interface/resources/qml/hifi/AssetServer.qml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 1ff954feff..526ea6aad0 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -39,6 +39,7 @@ Windows.ScrollingWindow { property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; property var selectedItemCount: treeView.selection.selectedIndexes.length; + property int updatesCount: 0; // this is used for notifying model-dependent bindings about model updates Settings { category: "Overlay.AssetServer" @@ -51,6 +52,9 @@ Windows.ScrollingWindow { ApplicationInterface.uploadRequest.connect(uploadClicked); assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); assetMappingsModel.autoRefreshEnabled = true; + assetMappingsModel.updated.connect(function() { + ++updatesCount; + }); reload(); } @@ -852,12 +856,17 @@ Windows.ScrollingWindow { checked = Qt.binding(isChecked); } + function getStatus() { + // kind of hack for ensuring getStatus() will be re-evaluated on updatesCount changes + return updatesCount, assetProxyModel.data(treeView.selection.currentIndex, 0x105); + } + function isEnabled() { if (!treeView.selection.hasSelection) { return false; } - var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); + var status = getStatus(); if (status === "--") { return false; } @@ -882,9 +891,9 @@ Windows.ScrollingWindow { return false; } - var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); - return isEnabled() && status !== "Not Baked"; - } + var status = getStatus(); + return isEnabled() && status !== "Not Baked"; + } } Item { From 7027ccb6d8ad626a2c230db45553852c00bbc957 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 30 Mar 2018 09:35:25 +1300 Subject: [PATCH 11/20] Remove unused code --- .../entities/src/EntityScriptingInterface.cpp | 23 ------------------- .../entities/src/EntityScriptingInterface.h | 1 - 2 files changed, 24 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c4a9956c90..2e9b386ba5 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -254,11 +254,6 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent); propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); - auto dimensions = propertiesWithSimID.getDimensions(); - float volume = dimensions.x * dimensions.y * dimensions.z; - auto density = propertiesWithSimID.getDensity(); - auto newVelocity = propertiesWithSimID.getVelocity().length(); - EntityItemID id = EntityItemID(QUuid::createUuid()); // If we have a local entity tree set, then also update it. @@ -370,12 +365,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& EntityItemProperties properties = scriptSideProperties; - auto dimensions = properties.getDimensions(); - float volume = dimensions.x * dimensions.y * dimensions.z; - auto density = properties.getDensity(); - auto newVelocity = properties.getVelocity().length(); - float oldVelocity = { 0.0f }; - EntityItemID entityID(id); if (!_entityTree) { queueEntityMessage(PacketType::EntityEdit, entityID, properties); @@ -400,9 +389,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& // All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them. // If any of these changed, pull any missing properties from the entity. - //existing entity, retrieve old velocity for check down below - oldVelocity = entity->getWorldVelocity().length(); - if (!scriptSideProperties.parentIDChanged()) { properties.setParentID(entity->getParentID()); } @@ -545,11 +531,6 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { return; } - auto dimensions = entity->getScaledDimensions(); - float volume = dimensions.x * dimensions.y * dimensions.z; - auto density = entity->getDensity(); - auto velocity = entity->getWorldVelocity().length(); - if (entity->getLocked()) { shouldDelete = false; } else { @@ -1770,10 +1751,6 @@ void EntityScriptingInterface::emitScriptEvent(const EntityItemID& entityID, con } } -float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) { - return std::abs(mass * (newVelocity - oldVelocity)); -} - // TODO move this someplace that makes more sense... bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, const glm::vec3& start, const glm::vec3& end, float radius) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index f92a88e0d2..4c2a2a47b4 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -122,7 +122,6 @@ public: void setEntityTree(EntityTreePointer modelTree); EntityTreePointer getEntityTree() { return _entityTree; } void setEntitiesScriptEngine(QSharedPointer engine); - float calculateCost(float mass, float oldVelocity, float newVelocity); void resetActivityTracking(); ActivityTracking getActivityTracking() const { return _activityTracking; } From 814cfa4587fd9eeb88b5ac13c9a7a12ec22b2d44 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Fri, 30 Mar 2018 00:09:28 +0300 Subject: [PATCH 12/20] fix TabletAssetServer --- .../qml/hifi/dialogs/TabletAssetServer.qml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 138eb5c6f8..6bf8f8a5d5 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -40,6 +40,7 @@ Rectangle { property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; property var selectedItemCount: treeView.selection.selectedIndexes.length; + property int updatesCount: 0; // this is used for notifying model-dependent bindings about model updates Settings { category: "Overlay.AssetServer" @@ -51,6 +52,9 @@ Rectangle { ApplicationInterface.uploadRequest.connect(uploadClicked); assetMappingsModel.errorGettingMappings.connect(handleGetMappingsError); assetMappingsModel.autoRefreshEnabled = true; + assetMappingsModel.updated.connect(function() { + ++updatesCount; + }); reload(); } @@ -850,12 +854,17 @@ Rectangle { checked = Qt.binding(isChecked); } + function getStatus() { + // kind of hack for ensuring getStatus() will be re-evaluated on updatesCount changes + return updatesCount, assetProxyModel.data(treeView.selection.currentIndex, 0x105); + } + function isEnabled() { if (!treeView.selection.hasSelection) { return false; } - var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); + var status = getStatus(); if (status === "--") { return false; } @@ -880,7 +889,7 @@ Rectangle { return false; } - var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); + var status = getStatus(); return isEnabled() && status !== "Not Baked"; } } From 5a7e9d8e3eb185e086f674b5d5984adf3d5e8457 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 30 Mar 2018 09:48:04 -0700 Subject: [PATCH 13/20] fix shadows on primitives --- libraries/entities-renderer/src/RenderableShapeEntityItem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index b05854da4e..feb88bed4b 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -131,6 +131,8 @@ ItemKey ShapeEntityRenderer::getKey() { withReadLock([&] { if (isTransparent()) { builder.withTransparent(); + } else if (_canCastShadow) { + builder.withShadowCaster(); } }); From d5496d68fd84456c2abb96e0c338345e4510b172 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 30 Mar 2018 16:58:41 -0700 Subject: [PATCH 14/20] FIx the mac crash when in front of a mirror by using the VIewFrustum stack correctly --- libraries/render-utils/src/AntialiasingEffect.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 4a9b69c099..ba5036ad68 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -380,6 +380,8 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const batch.setResourceTexture(AntialiasingPass_VelocityMapSlot, nullptr); batch.setResourceTexture(AntialiasingPass_NextMapSlot, nullptr); }); + + args->popViewFrustum(); } @@ -520,7 +522,7 @@ void JitterSample::run(const render::RenderContextPointer& renderContext) { viewFrustum.setProjection(projMat); viewFrustum.calculate(); - args->setViewFrustum(viewFrustum); + args->pushViewFrustum(viewFrustum); } else { mat4 projMats[2]; args->_context->getStereoProjections(projMats); @@ -538,4 +540,4 @@ void JitterSample::run(const render::RenderContextPointer& renderContext) { } -#endif \ No newline at end of file +#endif From 1f3063193a8e09409ffe5293a20a4ea75d68271f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 2 Apr 2018 14:24:51 -0700 Subject: [PATCH 15/20] Tweak right-click to inspect --- .../ui/overlays/ContextOverlayInterface.cpp | 29 ++++++++++++++++++- .../src/ui/overlays/ContextOverlayInterface.h | 6 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index dd05e5c6a8..aca186a589 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -50,7 +50,9 @@ ContextOverlayInterface::ContextOverlayInterface() { _entityPropertyFlags += PROP_OWNING_AVATAR_ID; auto entityScriptingInterface = DependencyManager::get().data(); - connect(entityScriptingInterface, &EntityScriptingInterface::mousePressOnEntity, this, &ContextOverlayInterface::createOrDestroyContextOverlay); + connect(entityScriptingInterface, &EntityScriptingInterface::clickDownOnEntity, this, &ContextOverlayInterface::clickDownOnEntity); + connect(entityScriptingInterface, &EntityScriptingInterface::holdingClickOnEntity, this, &ContextOverlayInterface::holdingClickOnEntity); + connect(entityScriptingInterface, &EntityScriptingInterface::mouseReleaseOnEntity, this, &ContextOverlayInterface::mouseReleaseOnEntity); connect(entityScriptingInterface, &EntityScriptingInterface::hoverEnterEntity, this, &ContextOverlayInterface::contextOverlays_hoverEnterEntity); connect(entityScriptingInterface, &EntityScriptingInterface::hoverLeaveEntity, this, &ContextOverlayInterface::contextOverlays_hoverLeaveEntity); connect(_tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"), &TabletProxy::tabletShownChanged, this, [&]() { @@ -97,6 +99,31 @@ void ContextOverlayInterface::setEnabled(bool enabled) { _enabled = enabled; } +void ContextOverlayInterface::clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { + if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID)) { + _mouseDownEntity = entityItemID; + _mouseDownEntityTimestamp = usecTimestampNow(); + } else { + if (!_currentEntityWithContextOverlay.isNull()) { + disableEntityHighlight(_currentEntityWithContextOverlay); + destroyContextOverlay(_currentEntityWithContextOverlay, event); + } + } +} + +static const float CONTEXT_OVERLAY_CLICK_HOLD_TIME_MSEC = 400.0f; +void ContextOverlayInterface::holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { + if (!_mouseDownEntity.isNull() && ((usecTimestampNow() - _mouseDownEntityTimestamp) > (CONTEXT_OVERLAY_CLICK_HOLD_TIME_MSEC * USECS_PER_MSEC))) { + _mouseDownEntity = EntityItemID(); + } +} + +void ContextOverlayInterface::mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event) { + if (_enabled && event.getButton() == PointerEvent::SecondaryButton && contextOverlayFilterPassed(entityItemID) && _mouseDownEntity == entityItemID) { + createOrDestroyContextOverlay(entityItemID, event); + } +} + bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) { if (_enabled && event.getButton() == PointerEvent::SecondaryButton) { if (contextOverlayFilterPassed(entityItemID)) { diff --git a/interface/src/ui/overlays/ContextOverlayInterface.h b/interface/src/ui/overlays/ContextOverlayInterface.h index fcdf2d5820..b80a3a70fb 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.h +++ b/interface/src/ui/overlays/ContextOverlayInterface.h @@ -64,6 +64,10 @@ signals: void contextOverlayClicked(const QUuid& currentEntityWithContextOverlay); public slots: + void clickDownOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + void holdingClickOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + void mouseReleaseOnEntity(const EntityItemID& entityItemID, const PointerEvent& event); + bool createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); bool destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event); bool destroyContextOverlay(const EntityItemID& entityItemID); @@ -84,6 +88,8 @@ private: }; bool _verboseLogging{ true }; bool _enabled { true }; + EntityItemID _mouseDownEntity{}; + quint64 _mouseDownEntityTimestamp; EntityItemID _currentEntityWithContextOverlay{}; EntityItemID _lastInspectedEntity{}; QString _entityMarketplaceID; From ccea3efe1e1d0714303d9c7aff54dc7a13db7b2c Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Mon, 2 Apr 2018 00:23:25 +0300 Subject: [PATCH 16/20] FB13789 - Log in/Sign up dialog is missing "Forgot Username?" and "Forgot Password?" links --- interface/resources/qml/controls-uit/TextField.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index f94541897b..6743d08275 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -163,10 +163,18 @@ TextField { text: textField.label colorScheme: textField.colorScheme anchors.left: parent.left - anchors.right: parent.right + + Binding on anchors.right { + when: parent.right + value: parent.right + } + Binding on wrapMode { + when: parent.right + value: Text.WordWrap + } + anchors.bottom: parent.top anchors.bottomMargin: 3 - wrapMode: Text.WordWrap visible: label != "" } } From 08b7326bd18d38d611a55e4ba59fd4be85ef2372 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Apr 2018 11:11:51 -0700 Subject: [PATCH 17/20] when moving a group of selections, don't move a child if a parent is being moved --- scripts/system/libraries/entitySelectionTool.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index fced5fc4e9..4fc767634b 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1618,8 +1618,16 @@ SelectionDisplay = (function() { grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), cornerPosition); - for (var i = 0; i < SelectionManager.selections.length; i++) { - var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; + var toMove = SelectionManager.selections.filter(function (selection) { + if (SelectionManager.selections.indexOf(SelectionManager.savedProperties[selection].parentID) >= 0) { + return false; // a parent is also being moved, so don't issue an edit for this entity + } else { + return true; + } + }); + + for (var i = 0; i < toMove.length; i++) { + var properties = SelectionManager.savedProperties[toMove[i]]; if (!properties) { continue; } @@ -1628,7 +1636,7 @@ SelectionDisplay = (function() { y: 0, z: vector.z }); - Entities.editEntity(SelectionManager.selections[i], { + Entities.editEntity(toMove[i], { position: newPosition }); From 249a97b5d0e474f3197c17d263910bbbdf3104ce Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Apr 2018 12:02:12 -0700 Subject: [PATCH 18/20] don't move or rotate children if a parent is being changed by the same action --- .../system/libraries/entitySelectionTool.js | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 4fc767634b..c84ecef722 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -1618,6 +1618,8 @@ SelectionDisplay = (function() { grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), cornerPosition); + // editing a parent will cause all the children to automatically follow along, so don't + // edit any entity who has an ancestor in SelectionManager.selections var toMove = SelectionManager.selections.filter(function (selection) { if (SelectionManager.selections.indexOf(SelectionManager.savedProperties[selection].parentID) >= 0) { return false; // a parent is also being moved, so don't issue an edit for this entity @@ -1735,9 +1737,19 @@ SelectionDisplay = (function() { Vec3.print(" newIntersection:", newIntersection); Vec3.print(" vector:", vector); } - - for (var i = 0; i < SelectionManager.selections.length; i++) { - var id = SelectionManager.selections[i]; + + // editing a parent will cause all the children to automatically follow along, so don't + // edit any entity who has an ancestor in SelectionManager.selections + var toMove = SelectionManager.selections.filter(function (selection) { + if (SelectionManager.selections.indexOf(SelectionManager.savedProperties[selection].parentID) >= 0) { + return false; // a parent is also being moved, so don't issue an edit for this entity + } else { + return true; + } + }); + + for (var i = 0; i < toMove.length; i++) { + var id = toMove[i]; var properties = SelectionManager.savedProperties[id]; var newPosition = Vec3.sum(properties.position, vector); Entities.editEntity(id, { position: newPosition }); @@ -2174,8 +2186,19 @@ SelectionDisplay = (function() { // the selections center point. Otherwise, the rotation will be around the entities // registration point which does not need repositioning. var reposition = (SelectionManager.selections.length > 1); - for (var i = 0; i < SelectionManager.selections.length; i++) { - var entityID = SelectionManager.selections[i]; + + // editing a parent will cause all the children to automatically follow along, so don't + // edit any entity who has an ancestor in SelectionManager.selections + var toRotate = SelectionManager.selections.filter(function (selection) { + if (SelectionManager.selections.indexOf(SelectionManager.savedProperties[selection].parentID) >= 0) { + return false; // a parent is also being moved, so don't issue an edit for this entity + } else { + return true; + } + }); + + for (var i = 0; i < toRotate.length; i++) { + var entityID = toRotate[i]; var initialProperties = SelectionManager.savedProperties[entityID]; var newProperties = { From f20eddefc8f6e345b6ce2859eaf1b4d76179b86d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 3 Apr 2018 13:46:02 -0700 Subject: [PATCH 19/20] Fix 'Private' HMD preview texture enable/disable...again --- .../qml/hifi/commerce/wallet/PassphraseChange.qml | 12 ++++++++++++ .../qml/hifi/commerce/wallet/PassphraseModal.qml | 4 ---- .../qml/hifi/commerce/wallet/PassphraseSelection.qml | 3 --- .../qml/hifi/commerce/wallet/SecurityImageChange.qml | 11 +++++++++++ .../hifi/commerce/wallet/SecurityImageSelection.qml | 12 ------------ .../resources/qml/hifi/commerce/wallet/Wallet.qml | 2 +- .../qml/hifi/commerce/wallet/WalletSetup.qml | 11 +++++++---- 7 files changed, 31 insertions(+), 24 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml index 91d2ab9f7f..e74b0fa9dc 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml @@ -24,6 +24,18 @@ Item { HifiConstants { id: hifi; } id: root; + + // This will cause a bug -- if you bring up passphrase selection in HUD mode while + // in HMD while having HMD preview enabled, then move, then finish passphrase selection, + // HMD preview will stay off. + // TODO: Fix this unlikely bug + onVisibleChanged: { + if (visible) { + sendSignalToWallet({method: 'disableHmdPreview'}); + } else { + sendSignalToWallet({method: 'maybeEnableHmdPreview'}); + } + } // Username Text RalewayRegular { diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index 1fa9054d69..7c38406697 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -68,10 +68,6 @@ Item { propagateComposedEvents: false; hoverEnabled: true; } - - Component.onDestruction: { - sendSignalToParent({method: 'maybeEnableHmdPreview'}); - } // This will cause a bug -- if you bring up passphrase selection in HUD mode while // in HMD while having HMD preview enabled, then move, then finish passphrase selection, diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 50bea2a3cf..5fd6b01d18 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -61,9 +61,6 @@ Item { if (root.shouldImmediatelyFocus) { focusFirstTextField(); } - sendMessageToLightbox({method: 'disableHmdPreview'}); - } else { - sendMessageToLightbox({method: 'maybeEnableHmdPreview'}); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index 86a4220b74..0d7fe9ed18 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -44,6 +44,17 @@ Item { } } + // This will cause a bug -- if you bring up security image selection in HUD mode while + // in HMD while having HMD preview enabled, then move, then finish passphrase selection, + // HMD preview will stay off. + // TODO: Fix this unlikely bug + onVisibleChanged: { + if (visible) { + sendSignalToWallet({method: 'disableHmdPreview'}); + } else { + sendSignalToWallet({method: 'maybeEnableHmdPreview'}); + } + } // Security Image Item { diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml index 56b78c5865..85fc0db3be 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml @@ -25,18 +25,6 @@ Item { id: root; property alias currentIndex: securityImageGrid.currentIndex; - - // This will cause a bug -- if you bring up security image selection in HUD mode while - // in HMD while having HMD preview enabled, then move, then finish passphrase selection, - // HMD preview will stay off. - // TODO: Fix this unlikely bug - onVisibleChanged: { - if (visible) { - sendSignalToWallet({method: 'disableHmdPreview'}); - } else { - sendSignalToWallet({method: 'maybeEnableHmdPreview'}); - } - } SecurityImageModel { id: gridModel; diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index b8b34dc395..b2e7daa066 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -237,7 +237,7 @@ Rectangle { } else { sendToScript(msg); } - } else if (msg.method === 'maybeEnableHmdPreview') { + } else { sendToScript(msg); } } diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml index bad592067c..6956252ee0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml @@ -76,6 +76,12 @@ Item { var currentStepNumber = root.activeView.substring(5); UserActivityLogger.commerceWalletSetupProgress(timestamp, root.setupAttemptID, Math.round((timestamp - root.startingTimestamp)/1000), currentStepNumber, root.setupStepNames[currentStepNumber - 1]); + + if (root.activeView === "step_2" || root.activeView === "step_3") { + sendSignalToWallet({method: 'disableHmdPreview'}); + } else { + sendSignalToWallet({method: 'maybeEnableHmdPreview'}); + } } // @@ -441,7 +447,7 @@ Item { } Item { id: choosePassphraseContainer; - visible: root.hasShownSecurityImageTip && root.activeView === "step_3"; + visible: root.activeView === "step_3"; // Anchors anchors.top: titleBarContainer.bottom; anchors.topMargin: 30; @@ -451,10 +457,7 @@ Item { onVisibleChanged: { if (visible) { - sendSignalToWallet({method: 'disableHmdPreview'}); Commerce.getWalletAuthenticatedStatus(); - } else { - sendSignalToWallet({method: 'maybeEnableHmdPreview'}); } } From 5f47d511718595422f93ff859fedc8bfcddaa74d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 3 Apr 2018 15:35:46 -0700 Subject: [PATCH 20/20] Prevent Context Overlay from flashing when briefly hovering over certified entity --- .../system/controllers/controllerModules/farActionGrabEntity.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 07450e54ba..d8e2a217a4 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -295,6 +295,7 @@ Script.include("/~/system/libraries/Xform.js"); this.actionID = null; this.grabbedThingID = null; this.targetObject = null; + this.potentialEntityWithContextOverlay = false; }; this.updateRecommendedArea = function() {