diff --git a/BUILD.md b/BUILD.md index feed677828..ba38f4b51d 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,7 +1,7 @@ ### Dependencies - [cmake](https://cmake.org/download/): 3.9 -- [Qt](https://www.qt.io/download-open-source): 5.9.1 +- [Qt](https://www.qt.io/download-open-source): 5.10.1 - [OpenSSL](https://www.openssl.org/): Use the latest available 1.0 version (**NOT** 1.1) of OpenSSL to avoid security vulnerabilities. - [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional) @@ -46,8 +46,8 @@ This can either be entered directly into your shell session before you build or The path it needs to be set to will depend on where and how Qt5 was installed. e.g. - export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.2/clang_64/lib/cmake/ - export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.6.2/lib/cmake + export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.10.1/clang_64/lib/cmake/ + export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.10.1/lib/cmake export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake #### Generating build files @@ -66,7 +66,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation: - cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.6.2/lib/cmake + cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.10.1/lib/cmake #### Finding Dependencies diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 038f53154c..64c0e9a643 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -14,8 +14,8 @@ Should you choose not to install Qt5 via a package manager that handles dependen Install qt: ```bash -wget http://debian.highfidelity.com/pool/h/hi/hifi-qt5.6.1_5.6.1_amd64.deb -sudo dpkg -i hifi-qt5.6.1_5.6.1_amd64.deb +wget http://debian.highfidelity.com/pool/h/hi/hifi-qt5.10.1_5.10.1_amd64.deb +sudo dpkg -i hifi-qt5.10.1_5.10.1_amd64.deb ``` Install build dependencies: @@ -66,7 +66,7 @@ cd hifi/build Prepare makefiles: ```bash -cmake -DQT_CMAKE_PREFIX_PATH=/usr/local/Qt5.6.1/5.6/gcc_64/lib/cmake .. +cmake -DQT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10/gcc_64/lib/cmake .. ``` Start compilation and get a cup of coffee: @@ -74,7 +74,7 @@ Start compilation and get a cup of coffee: make domain-server assignment-client interface ``` -In a server does not make sense to compile interface +In a server does not make sense to compile interface ### Running the software diff --git a/BUILD_OSX.md b/BUILD_OSX.md index 6b66863534..62102b3e18 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -20,7 +20,7 @@ Note that this uses the version from the homebrew formula at the time of this wr Assuming you've installed Qt using the homebrew instructions above, you'll need to set QT_CMAKE_PREFIX_PATH so CMake can find your installations. For Qt installed via homebrew, set QT_CMAKE_PREFIX_PATH: - export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt/5.9.1/lib/cmake + export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt/5.10.1/lib/cmake Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change. diff --git a/BUILD_WIN.md b/BUILD_WIN.md index eea1f85e5b..3222e75c66 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -1,13 +1,13 @@ This is a stand-alone guide for creating your first High Fidelity build for Windows 64-bit. ## Building High Fidelity -Note: We are now using Visual Studio 2017 and Qt 5.9.1. If you are upgrading from Visual Studio 2013 and Qt 5.6.2, do a clean uninstall of those versions before going through this guide. +Note: We are now using Visual Studio 2017 and Qt 5.10.1. If you are upgrading from Visual Studio 2013 and Qt 5.6.2, do a clean uninstall of those versions before going through this guide. Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory. ### Step 1. Visual Studio 2017 -If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/). +If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/). When selecting components, check "Desktop development with C++." Also check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)" on the Summary toolbar on the right. @@ -17,15 +17,15 @@ Download and install the latest version of CMake 3.9. Download the file named w ### Step 3. Installing Qt -Download and install the [Qt Online Installer](https://www.qt.io/download-open-source/?hsCtaTracking=f977210e-de67-475f-a32b-65cec207fd03%7Cd62710cd-e1db-46aa-8d4d-2f1c1ffdacea). While installing, you only need to have the following components checked under Qt 5.9.1: "msvc2017 64-bit", "Qt WebEngine", and "Qt Script (Deprecated)". +Download and install the [Qt Online Installer](https://www.qt.io/download-open-source/?hsCtaTracking=f977210e-de67-475f-a32b-65cec207fd03%7Cd62710cd-e1db-46aa-8d4d-2f1c1ffdacea). While installing, you only need to have the following components checked under Qt 5.10.1: "msvc2017 64-bit", "Qt WebEngine", and "Qt Script (Deprecated)". -Note: Installing the Sources is optional but recommended if you have room for them (~2GB). +Note: Installing the Sources is optional but recommended if you have room for them (~2GB). ### Step 4. Setting Qt Environment Variable Go to `Control Panel > System > Advanced System Settings > Environment Variables > New...` (or search “Environment Variables” in Start Search). * Set "Variable name": `QT_CMAKE_PREFIX_PATH` -* Set "Variable value": `C:\Qt\5.9.1\msvc2017_64\lib\cmake` +* Set "Variable value": `C:\Qt\5.10.1\msvc2017_64\lib\cmake` ### Step 5. Installing [vcpkg](https://github.com/Microsoft/vcpkg) @@ -39,7 +39,7 @@ Go to `Control Panel > System > Advanced System Settings > Environment Variables * In the vcpkg directory, install the 64 bit OpenSSL package with the command `vcpkg install openssl:x64-windows` * Once the build completes you should have a file `ssl.h` in `${VCPKG_ROOT}/installed/x64-windows/include/openssl` - + ### Step 7. Running CMake to Generate Build Files Run Command Prompt from Start and run the following commands: @@ -49,7 +49,7 @@ mkdir build cd build cmake .. -G "Visual Studio 15 Win64" ``` - + Where `%HIFI_DIR%` is the directory for the highfidelity repository. ### Step 8. Making a Build @@ -74,10 +74,10 @@ Note: You can also run Interface by launching it from command line or File Explo ## Troubleshooting -For any problems after Step #7, first try this: +For any problems after Step #7, first try this: * Delete your locally cloned copy of the highfidelity repository * Restart your computer -* Redownload the [repository](https://github.com/highfidelity/hifi) +* Redownload the [repository](https://github.com/highfidelity/hifi) * Restart directions from Step #7 #### CMake gives you the same error message repeatedly after the build fails @@ -90,4 +90,4 @@ Remove `CMakeCache.txt` found in the `%HIFI_DIR%\build` directory. Verify that #### Qt is throwing an error -Make sure you have the correct version (5.9.1) installed and `QT_CMAKE_PREFIX_PATH` environment variable is set correctly. +Make sure you have the correct version (5.10.1) installed and `QT_CMAKE_PREFIX_PATH` environment variable is set correctly. diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index ccdd2fca4f..3c8e38f278 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -322,8 +322,16 @@ void AudioMixerSlave::addStream(AudioMixerClientData& listenerNodeData, const QU // stereo sources are not passed through HRTF if (streamToAdd.isStereo()) { - for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; ++i) { - _mixSamples[i] += float(streamPopOutput[i] * gain / AudioConstants::MAX_SAMPLE_VALUE); + + // apply the avatar gain adjustment + auto& hrtf = listenerNodeData.hrtfForStream(sourceNodeID, streamToAdd.getStreamIdentifier()); + gain *= hrtf.getGainAdjustment(); + + const float scale = 1/32768.0f; // int16_t to float + + for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; i++) { + _mixSamples[2*i+0] += (float)streamPopOutput[2*i+0] * gain * scale; + _mixSamples[2*i+1] += (float)streamPopOutput[2*i+1] * gain * scale; } ++stats.manualStereoMixes; @@ -332,10 +340,13 @@ void AudioMixerSlave::addStream(AudioMixerClientData& listenerNodeData, const QU // echo sources are not passed through HRTF if (isEcho) { - for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; i += 2) { - auto monoSample = float(streamPopOutput[i / 2] * gain / AudioConstants::MAX_SAMPLE_VALUE); - _mixSamples[i] += monoSample; - _mixSamples[i + 1] += monoSample; + + const float scale = 1/32768.0f; // int16_t to float + + for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; i++) { + float sample = (float)streamPopOutput[i] * gain * scale; + _mixSamples[2*i+0] += sample; + _mixSamples[2*i+1] += sample; } ++stats.manualEchoMixes; diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index d2bcbf2886..e3aca52ee5 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -363,7 +363,9 @@ void EntityServer::nodeAdded(SharedNodePointer node) { void EntityServer::nodeKilled(SharedNodePointer node) { EntityTreePointer tree = std::static_pointer_cast(_tree); - tree->deleteDescendantsOfAvatar(node->getUUID()); + tree->withWriteLock([&] { + tree->deleteDescendantsOfAvatar(node->getUUID()); + }); tree->forgetAvatarID(node->getUUID()); OctreeServer::nodeKilled(node); } @@ -451,8 +453,6 @@ void EntityServer::domainSettingsRequestFailed() { void EntityServer::startDynamicDomainVerification() { qCDebug(entities) << "Starting Dynamic Domain Verification..."; - QString thisDomainID = DependencyManager::get()->getDomainID().remove(QRegExp("\\{|\\}")); - EntityTreePointer tree = std::static_pointer_cast(_tree); QHash localMap(tree->getEntityCertificateIDMap()); @@ -460,15 +460,19 @@ void EntityServer::startDynamicDomainVerification() { qCDebug(entities) << localMap.size() << "entities in _entityCertificateIDMap"; while (i.hasNext()) { i.next(); + const auto& certificateID = i.key(); + const auto& entityID = i.value(); - EntityItemPointer entity = tree->findEntityByEntityItemID(i.value()); + EntityItemPointer entity = tree->findEntityByEntityItemID(entityID); if (entity) { if (!entity->getProperties().verifyStaticCertificateProperties()) { - qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << i.value() << "failed" + qCDebug(entities) << "During Dynamic Domain Verification, a certified entity with ID" << entityID << "failed" << "static certificate verification."; // Delete the entity if it doesn't pass static certificate verification - tree->deleteEntity(i.value(), true); + tree->withWriteLock([&] { + tree->deleteEntity(entityID, true); + }); } else { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest; @@ -477,39 +481,46 @@ void EntityServer::startDynamicDomainVerification() { QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL(); requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/location"); QJsonObject request; - request["certificate_id"] = i.key(); + request["certificate_id"] = certificateID; networkRequest.setUrl(requestURL); - QNetworkReply* networkReply = NULL; - networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); + QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); + + connect(networkReply, &QNetworkReply::finished, this, [this, entityID, networkReply] { + EntityTreePointer tree = std::static_pointer_cast(_tree); - connect(networkReply, &QNetworkReply::finished, [=]() { QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); jsonObject = jsonObject["data"].toObject(); if (networkReply->error() == QNetworkReply::NoError) { + QString thisDomainID = DependencyManager::get()->getDomainID().remove(QRegExp("\\{|\\}")); if (jsonObject["domain_id"].toString() != thisDomainID) { + EntityItemPointer entity = tree->findEntityByEntityItemID(entityID); if (entity->getAge() > (_MAXIMUM_DYNAMIC_DOMAIN_VERIFICATION_TIMER_MS/MSECS_PER_SECOND)) { qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString() - << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << i.value(); - tree->deleteEntity(i.value(), true); + << "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << entityID; + tree->withWriteLock([&] { + tree->deleteEntity(entityID, true); + }); } else { - qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << i.value(); + qCDebug(entities) << "Entity failed dynamic domain verification, but was created too recently to necessitate deletion:" << entityID; } } else { - qCDebug(entities) << "Entity passed dynamic domain verification:" << i.value(); + qCDebug(entities) << "Entity passed dynamic domain verification:" << entityID; } } else { - qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << i.value() + qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << entityID << "More info:" << jsonObject; - tree->deleteEntity(i.value(), true); + tree->withWriteLock([&] { + tree->deleteEntity(entityID, true); + }); } networkReply->deleteLater(); }); } } else { - qCWarning(entities) << "During DDV, an entity with ID" << i.value() << "was NOT found in the Entity Tree!"; + qCWarning(entities) << "During DDV, an entity with ID" << entityID << "was NOT found in the Entity Tree!"; } } diff --git a/assignment-client/src/entities/EntityTreeSendThread.cpp b/assignment-client/src/entities/EntityTreeSendThread.cpp index 94d21f1c9a..4aa52922c0 100644 --- a/assignment-client/src/entities/EntityTreeSendThread.cpp +++ b/assignment-client/src/entities/EntityTreeSendThread.cpp @@ -311,7 +311,8 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); _entitiesInQueue.insert(entity.get()); } - } else if (entity->getLastEdited() > knownTimestamp->second) { + } else if (entity->getLastEdited() > knownTimestamp->second + || entity->getLastChangedOnServer() > knownTimestamp->second) { // it is known and it changed --> put it on the queue with any priority // TODO: sort these correctly _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); @@ -330,7 +331,9 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree return; } auto knownTimestamp = _knownState.find(entity.get()); - if (knownTimestamp == _knownState.end() || entity->getLastEdited() > knownTimestamp->second) { + if (knownTimestamp == _knownState.end() + || entity->getLastEdited() > knownTimestamp->second + || entity->getLastChangedOnServer() > knownTimestamp->second) { _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); _entitiesInQueue.insert(entity.get()); } @@ -382,7 +385,8 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTree _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); _entitiesInQueue.insert(entity.get()); } - } else if (entity->getLastEdited() > knownTimestamp->second) { + } else if (entity->getLastEdited() > knownTimestamp->second + || entity->getLastChangedOnServer() > knownTimestamp->second) { // it is known and it changed --> put it on the queue with any priority // TODO: sort these correctly _sendQueue.push(PrioritizedEntity(entity, PrioritizedEntity::WHEN_IN_DOUBT_PRIORITY)); diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index d5b9da7353..715e83f403 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -400,7 +400,9 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* if (shouldTraverseAndSend(nodeData)) { quint64 start = usecTimestampNow(); - traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); + _myServer->getOctree()->withReadLock([&]{ + traverseTreeAndSendContents(node, nodeData, viewFrustumChanged, isFullScene); + }); // Here's where we can/should allow the server to send other data... // send the environment packet diff --git a/cmake/externals/crashpad/CMakeLists.txt b/cmake/externals/crashpad/CMakeLists.txt index c464dcbc1b..e509e115e4 100644 --- a/cmake/externals/crashpad/CMakeLists.txt +++ b/cmake/externals/crashpad/CMakeLists.txt @@ -6,8 +6,8 @@ string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) if (WIN32) ExternalProject_Add( ${EXTERNAL_NAME} - URL https://backtrace.io/download/crashpad_062317.zip - URL_MD5 65817e564b3628492abfc1dbd2a1e98b + URL http://public.highfidelity.com/dependencies/crashpad_062317.1.zip + URL_MD5 9c84b77f5f23daf939da1371825ed2b1 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" diff --git a/cmake/externals/serverless-content/CMakeLists.txt b/cmake/externals/serverless-content/CMakeLists.txt index 4d0773f5f5..a08b589ec2 100644 --- a/cmake/externals/serverless-content/CMakeLists.txt +++ b/cmake/externals/serverless-content/CMakeLists.txt @@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC66-v2.zip - URL_MD5 d76bdb3e2bf7ae5d20115bd97b0c44a8 + URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC66-v4.zip + URL_MD5 d4f42f630986c83427ff39e1fe9908c6 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" diff --git a/cmake/macros/SetupQt.cmake b/cmake/macros/SetupQt.cmake index 00a398761b..71f5314d2f 100644 --- a/cmake/macros/SetupQt.cmake +++ b/cmake/macros/SetupQt.cmake @@ -1,10 +1,10 @@ -# +# # Created by Bradley Austin Davis on 2017/09/02 # Copyright 2013-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 -# +# # Construct a default QT location from a root path, a version and an architecture function(calculate_default_qt_dir _RESULT_NAME) @@ -27,7 +27,7 @@ function(calculate_default_qt_dir _RESULT_NAME) endif() set_from_env(QT_ROOT QT_ROOT ${QT_DEFAULT_ROOT}) - set_from_env(QT_VERSION QT_VERSION "5.9.1") + set_from_env(QT_VERSION QT_VERSION "5.10.1") set_from_env(QT_ARCH QT_ARCH ${QT_DEFAULT_ARCH}) set(${_RESULT_NAME} "${QT_ROOT}/${QT_VERSION}/${QT_ARCH}" PARENT_SCOPE) @@ -60,11 +60,11 @@ macro(setup_qt) #if (NOT EXISTS "${QT_DIR}/include/QtCore/QtGlobal") # message(FATAL_ERROR "Unable to locate Qt includes in ${QT_DIR}") #endif() - + if (NOT EXISTS "${QT_CMAKE_PREFIX_PATH}/Qt5Core/Qt5CoreConfig.cmake") message(FATAL_ERROR "Unable to locate Qt cmake config in ${QT_CMAKE_PREFIX_PATH}") endif() - + message(STATUS "The Qt build in use is: \"${QT_DIR}\"") # Instruct CMake to run moc automatically when needed. @@ -72,7 +72,7 @@ macro(setup_qt) # Instruct CMake to run rcc automatically when needed set(CMAKE_AUTORCC ON) - + if (WIN32) add_paths_to_fixup_libs("${QT_DIR}/bin") endif () diff --git a/cmake/modules/FindGverb.cmake b/cmake/modules/FindGverb.cmake deleted file mode 100644 index 0c149a7ca1..0000000000 --- a/cmake/modules/FindGverb.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# FindGVerb.cmake -# -# Try to find the Gverb library. -# -# You must provide a GVERB_ROOT_DIR which contains src and include directories -# -# Once done this will define -# -# GVERB_FOUND - system found Gverb -# GVERB_INCLUDE_DIRS - the Gverb include directory -# -# 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 -# - -include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("gverb") - -find_path(GVERB_INCLUDE_DIRS gverb.h PATH_SUFFIXES include HINTS ${GVERB_SEARCH_DIRS}) -find_library(GVERB_LIBRARIES gverb PATH_SUFFIXES lib HINTS ${GVERB_SEARCH_DIRS}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Gverb DEFAULT_MSG GVERB_INCLUDE_DIRS GVERB_LIBRARIES) \ No newline at end of file diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index bdedf4cbba..28ac320e42 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -1234,6 +1234,9 @@ Section "Uninstall" @CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ + ;Remove the installer information file + Delete "$INSTDIR\installer.ini" + ;Remove files we installed. ;Keep the list of directories here in sync with the File commands above. @CPACK_NSIS_DELETE_FILES@ diff --git a/interface/resources/QtWebEngine/UIDelegates/AlertDialog.qml b/interface/resources/QtWebEngine/UIDelegates/AlertDialog.qml index e6dc03fa55..bf72869752 100644 --- a/interface/resources/QtWebEngine/UIDelegates/AlertDialog.qml +++ b/interface/resources/QtWebEngine/UIDelegates/AlertDialog.qml @@ -1,6 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.0 import "../../qml/dialogs" diff --git a/interface/resources/QtWebEngine/UIDelegates/FilePicker.qml b/interface/resources/QtWebEngine/UIDelegates/FilePicker.qml index cb6552b075..55f7d27534 100644 --- a/interface/resources/QtWebEngine/UIDelegates/FilePicker.qml +++ b/interface/resources/QtWebEngine/UIDelegates/FilePicker.qml @@ -1,6 +1,4 @@ import QtQuick 2.4 -import QtQuick.Dialogs 1.1 -import QtQuick.Controls 1.4 import "../../qml/dialogs" diff --git a/interface/resources/QtWebEngine/UIDelegates/Menu.qml b/interface/resources/QtWebEngine/UIDelegates/Menu.qml index 1bbbbd6cbe..46c00e758e 100644 --- a/interface/resources/QtWebEngine/UIDelegates/Menu.qml +++ b/interface/resources/QtWebEngine/UIDelegates/Menu.qml @@ -1,5 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 as Controls import "../../qml/controls-uit" import "../../qml/styles-uit" diff --git a/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml b/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml index 1890fcb81d..6014b6834b 100644 --- a/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml +++ b/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml @@ -1,6 +1,4 @@ - import QtQuick 2.5 -import QtQuick.Controls 1.4 as Controls import "../../qml/controls-uit" import "../../qml/styles-uit" diff --git a/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml b/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml index 01d3262bc0..e4ab3037ef 100644 --- a/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml +++ b/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml @@ -1,6 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.0 import "../../qml/controls-uit" import "../../qml/styles-uit" diff --git a/interface/resources/qml/AvatarInputsBar.qml b/interface/resources/qml/AvatarInputsBar.qml index a88a42080e..4a071d2d04 100644 --- a/interface/resources/qml/AvatarInputsBar.qml +++ b/interface/resources/qml/AvatarInputsBar.qml @@ -8,9 +8,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.4 -import QtQuick.Controls 1.3 -import QtGraphicalEffects 1.0 -import Qt.labs.settings 1.0 import "./hifi/audio" as HifiAudio diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index f1dd3c8350..f0475dfebd 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,5 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.2 import QtWebChannel 1.0 import QtWebEngine 1.5 diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 0e2f2a5282..4708bfdebe 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -174,7 +174,7 @@ Item { } } - CheckBoxQQC2 { + CheckBox { id: showPassword text: "Show password" } diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index 9d55998b40..5eb99e0ece 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -11,7 +11,6 @@ import Hifi 1.0 import QtQuick 2.7 import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 as OriginalStyles import "../controls-uit" import "../styles-uit" diff --git a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml index 5c212578b8..bf05a36ce1 100644 --- a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml +++ b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml @@ -11,7 +11,6 @@ import Hifi 1.0 import QtQuick 2.4 import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 as OriginalStyles import "../controls-uit" import "../styles-uit" diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index d2daf0fa1d..d73a574081 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import QtWebEngine 1.1 import QtWebChannel 1.0 diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index 7c1ce704c3..bef6423e25 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -1,9 +1,4 @@ - import QtQuick 2.3 -import QtQuick.Controls 1.4 -import QtWebChannel 1.0 -import QtWebEngine 1.2 -import QtWebSockets 1.0 import "windows" as Windows import "controls" diff --git a/interface/resources/qml/StatText.qml b/interface/resources/qml/StatText.qml index 69963c1373..9fefbd28b8 100644 --- a/interface/resources/qml/StatText.qml +++ b/interface/resources/qml/StatText.qml @@ -1,5 +1,4 @@ import QtQuick 2.3 -import QtQuick.Controls 1.2 Text { color: "white"; diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 4626d9bcda..d961285a46 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -1,6 +1,5 @@ import Hifi 1.0 as Hifi import QtQuick 2.3 -import QtQuick.Controls 1.2 import '.' Item { diff --git a/interface/resources/qml/TabletBrowser.qml b/interface/resources/qml/TabletBrowser.qml index 8dbcc8f4f8..141c1f25a7 100644 --- a/interface/resources/qml/TabletBrowser.qml +++ b/interface/resources/qml/TabletBrowser.qml @@ -1,5 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 import QtWebChannel 1.0 import QtWebEngine 1.5 diff --git a/interface/resources/qml/Web3DOverlay.qml b/interface/resources/qml/Web3DOverlay.qml index a1fa2d2641..fdd5d8a7c6 100644 --- a/interface/resources/qml/Web3DOverlay.qml +++ b/interface/resources/qml/Web3DOverlay.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "controls" as Controls diff --git a/interface/resources/qml/controller/AnalogButton.qml b/interface/resources/qml/controller/AnalogButton.qml index 82beb818ab..6539bc793d 100644 --- a/interface/resources/qml/controller/AnalogButton.qml +++ b/interface/resources/qml/controller/AnalogButton.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 Item { id: root diff --git a/interface/resources/qml/controller/AnalogStick.qml b/interface/resources/qml/controller/AnalogStick.qml index c0d10bac59..d7b52a6319 100644 --- a/interface/resources/qml/controller/AnalogStick.qml +++ b/interface/resources/qml/controller/AnalogStick.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 Item { id: root diff --git a/interface/resources/qml/controller/Hydra.qml b/interface/resources/qml/controller/Hydra.qml index 19f3b4c193..e5c918cc77 100644 --- a/interface/resources/qml/controller/Hydra.qml +++ b/interface/resources/qml/controller/Hydra.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import "hydra" diff --git a/interface/resources/qml/controller/Standard.qml b/interface/resources/qml/controller/Standard.qml index 45e4febfa2..1c51a527cd 100644 --- a/interface/resources/qml/controller/Standard.qml +++ b/interface/resources/qml/controller/Standard.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import "xbox" diff --git a/interface/resources/qml/controller/ToggleButton.qml b/interface/resources/qml/controller/ToggleButton.qml index ee8bd380e2..567191bd25 100644 --- a/interface/resources/qml/controller/ToggleButton.qml +++ b/interface/resources/qml/controller/ToggleButton.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 Item { id: root diff --git a/interface/resources/qml/controller/Xbox.qml b/interface/resources/qml/controller/Xbox.qml index 4ff2959129..71f99c2081 100644 --- a/interface/resources/qml/controller/Xbox.qml +++ b/interface/resources/qml/controller/Xbox.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import "xbox" diff --git a/interface/resources/qml/controller/hydra/HydraButtons.qml b/interface/resources/qml/controller/hydra/HydraButtons.qml index aa8927f5b6..f579527a1f 100644 --- a/interface/resources/qml/controller/hydra/HydraButtons.qml +++ b/interface/resources/qml/controller/hydra/HydraButtons.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import ".." diff --git a/interface/resources/qml/controller/hydra/HydraStick.qml b/interface/resources/qml/controller/hydra/HydraStick.qml index d082a20b10..7b5ce41c76 100644 --- a/interface/resources/qml/controller/hydra/HydraStick.qml +++ b/interface/resources/qml/controller/hydra/HydraStick.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import ".." diff --git a/interface/resources/qml/controller/xbox/DPad.qml b/interface/resources/qml/controller/xbox/DPad.qml index 2cfb6412e7..20eda19648 100644 --- a/interface/resources/qml/controller/xbox/DPad.qml +++ b/interface/resources/qml/controller/xbox/DPad.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import ".." diff --git a/interface/resources/qml/controller/xbox/LeftAnalogStick.qml b/interface/resources/qml/controller/xbox/LeftAnalogStick.qml index 8e2de1eb36..430d6f39a4 100644 --- a/interface/resources/qml/controller/xbox/LeftAnalogStick.qml +++ b/interface/resources/qml/controller/xbox/LeftAnalogStick.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import ".." diff --git a/interface/resources/qml/controller/xbox/RightAnalogStick.qml b/interface/resources/qml/controller/xbox/RightAnalogStick.qml index 0cdfeda2cf..89e93aa8bc 100644 --- a/interface/resources/qml/controller/xbox/RightAnalogStick.qml +++ b/interface/resources/qml/controller/xbox/RightAnalogStick.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import ".." diff --git a/interface/resources/qml/controller/xbox/XboxButtons.qml b/interface/resources/qml/controller/xbox/XboxButtons.qml index e26a4a0b98..5c68fcff72 100644 --- a/interface/resources/qml/controller/xbox/XboxButtons.qml +++ b/interface/resources/qml/controller/xbox/XboxButtons.qml @@ -1,7 +1,4 @@ import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 import ".." diff --git a/interface/resources/qml/controls-uit/+android/Button.qml b/interface/resources/qml/controls-uit/+android/Button.qml new file mode 100644 index 0000000000..2f05b35685 --- /dev/null +++ b/interface/resources/qml/controls-uit/+android/Button.qml @@ -0,0 +1,125 @@ +// +// Button.qml +// +// Created by David Rowe on 16 Feb 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 as Original +import QtQuick.Controls.Styles 1.4 +import TabletScriptingInterface 1.0 + +import "../styles-uit" + +Original.Button { + id: root; + + property int color: 0 + property int colorScheme: hifi.colorSchemes.light + property string buttonGlyph: ""; + + width: hifi.dimensions.buttonWidth + height: hifi.dimensions.controlLineHeight + + HifiConstants { id: hifi } + + onHoveredChanged: { + if (hovered) { + Tablet.playSound(TabletEnums.ButtonHover); + } + } + + onFocusChanged: { + if (focus) { + Tablet.playSound(TabletEnums.ButtonHover); + } + } + + onClicked: { + Tablet.playSound(TabletEnums.ButtonClick); + } + + style: ButtonStyle { + + background: Rectangle { + radius: hifi.buttons.radius + + border.width: (control.color === hifi.buttons.none || + (control.color === hifi.buttons.noneBorderless && control.hovered) || + (control.color === hifi.buttons.noneBorderlessWhite && control.hovered) || + (control.color === hifi.buttons.noneBorderlessGray && control.hovered)) ? 1 : 0; + border.color: control.color === hifi.buttons.noneBorderless ? hifi.colors.blueHighlight : + (control.color === hifi.buttons.noneBorderlessGray ? hifi.colors.baseGray : hifi.colors.white); + + gradient: Gradient { + GradientStop { + position: 0.2 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorStart[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] + } else if (!control.hovered && control.focus) { + hifi.buttons.focusedColor[control.color] + } else { + hifi.buttons.colorStart[control.color] + } + } + } + GradientStop { + position: 1.0 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorFinish[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] + } else if (!control.hovered && control.focus) { + hifi.buttons.focusedColor[control.color] + } else { + hifi.buttons.colorFinish[control.color] + } + } + } + } + } + + label: Item { + HiFiGlyphs { + id: buttonGlyph; + visible: root.buttonGlyph !== ""; + text: root.buttonGlyph === "" ? hifi.glyphs.question : root.buttonGlyph; + // Size + size: 34; + // Anchors + anchors.right: buttonText.left; + anchors.top: parent.top; + anchors.bottom: parent.bottom; + // Style + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme]; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + RalewayBold { + id: buttonText; + anchors.centerIn: parent; + font.capitalization: Font.AllUppercase + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme] + size: hifi.fontSizes.buttonLabel + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + } + } + } +} diff --git a/interface/resources/qml/controls-uit/+android/Table.qml b/interface/resources/qml/controls-uit/+android/Table.qml new file mode 100644 index 0000000000..3c1d0fcd3c --- /dev/null +++ b/interface/resources/qml/controls-uit/+android/Table.qml @@ -0,0 +1,165 @@ +// +// Table.qml +// +// Created by David Rowe on 18 Feb 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.2 as QQC2 + +import "../styles-uit" + +TableView { + id: tableView + + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + property bool expandSelectedRow: false + property bool centerHeaderText: false + readonly property real headerSpacing: 3 //spacing between sort indicator and table header title + property var titlePaintedPos: [] // storing extra data position behind painted + // title text and sort indicatorin table's header + signal titlePaintedPosSignal(int column) //signal that extradata position gets changed + + model: ListModel { } + + Component.onCompleted: { + if (flickableItem !== null && flickableItem !== undefined) { + tableView.flickableItem.QQC2.ScrollBar.vertical = scrollbar + } + } + + QQC2.ScrollBar { + id: scrollbar + parent: tableView.flickableItem + policy: QQC2.ScrollBar.AsNeeded + orientation: Qt.Vertical + visible: size < 1.0 + topPadding: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight + 1 : 1 + anchors.top: tableView.top + anchors.left: tableView.right + anchors.bottom: tableView.bottom + + background: Item { + implicitWidth: hifi.dimensions.scrollbarBackgroundWidth + Rectangle { + anchors { + fill: parent; + topMargin: tableView.headerVisible ? hifi.dimensions.tableHeaderHeight : 0 + } + color: isLightColorScheme ? hifi.colors.tableScrollBackgroundLight + : hifi.colors.tableScrollBackgroundDark + } + } + + contentItem: Item { + implicitWidth: hifi.dimensions.scrollbarHandleWidth + Rectangle { + anchors.fill: parent + radius: (width - 4)/2 + color: isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark + } + } + } + + headerVisible: false + headerDelegate: Rectangle { + height: hifi.dimensions.tableHeaderHeight + color: isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark + + + RalewayRegular { + id: titleText + x: centerHeaderText ? (parent.width - paintedWidth - + ((sortIndicatorVisible && + sortIndicatorColumn === styleData.column) ? + (titleSort.paintedWidth / 5 + tableView.headerSpacing) : 0)) / 2 : + hifi.dimensions.tablePadding + text: styleData.value + size: hifi.fontSizes.tableHeading + font.capitalization: Font.AllUppercase + color: hifi.colors.baseGrayHighlight + horizontalAlignment: (centerHeaderText ? Text.AlignHCenter : Text.AlignLeft) + anchors.verticalCenter: parent.verticalCenter + } + + //actual image of sort indicator in glyph font only 20% of real font size + //i.e. if the charachter size set to 60 pixels, actual image is 12 pixels + HiFiGlyphs { + id: titleSort + text: sortIndicatorOrder == Qt.AscendingOrder ? hifi.glyphs.caratUp : hifi.glyphs.caratDn + color: hifi.colors.darkGray + opacity: 0.6; + size: hifi.fontSizes.tableHeadingIcon + anchors.verticalCenter: titleText.verticalCenter + anchors.left: titleText.right + anchors.leftMargin: -(hifi.fontSizes.tableHeadingIcon / 2.5) + tableView.headerSpacing + visible: sortIndicatorVisible && sortIndicatorColumn === styleData.column + onXChanged: { + titlePaintedPos[styleData.column] = titleText.x + titleText.paintedWidth + + paintedWidth / 5 + tableView.headerSpacing*2 + titlePaintedPosSignal(styleData.column) + } + } + + Rectangle { + width: 1 + anchors { + left: parent.left + top: parent.top + topMargin: 1 + bottom: parent.bottom + bottomMargin: 2 + } + color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight + visible: styleData.column > 0 + } + + Rectangle { + height: 1 + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight + } + } + + // Use rectangle to draw border with rounded corners. + frameVisible: false + Rectangle { + color: "#00000000" + anchors { fill: parent; margins: -2 } + border.color: isLightColorScheme ? hifi.colors.lightGrayText : hifi.colors.baseGrayHighlight + border.width: 2 + } + anchors.margins: 2 // Shrink TableView to lie within border. + + backgroundVisible: true + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + style: TableViewStyle { + // Needed in order for rows to keep displaying rows after end of table entries. + backgroundColor: tableView.isLightColorScheme ? hifi.colors.tableBackgroundLight : hifi.colors.tableBackgroundDark + alternateBackgroundColor: tableView.isLightColorScheme ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd + padding.top: headerVisible ? hifi.dimensions.tableHeaderHeight: 0 + } + + rowDelegate: Rectangle { + height: (styleData.selected && expandSelectedRow ? 1.8 : 1) * hifi.dimensions.tableRowHeight + color: styleData.selected + ? hifi.colors.primaryHighlight + : tableView.isLightColorScheme + ? (styleData.alternate ? hifi.colors.tableRowLightEven : hifi.colors.tableRowLightOdd) + : (styleData.alternate ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd) + } +} diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controls-uit/Button.qml index e2b6097553..0119d76ac2 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -8,15 +8,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.3 as Original import TabletScriptingInterface 1.0 import "../styles-uit" Original.Button { - id: root; + id: control; property int color: 0 property int colorScheme: hifi.colorSchemes.light @@ -38,88 +37,86 @@ Original.Button { Tablet.playSound(TabletEnums.ButtonHover); } } - + onClicked: { Tablet.playSound(TabletEnums.ButtonClick); } - style: ButtonStyle { + background: Rectangle { + radius: hifi.buttons.radius - background: Rectangle { - radius: hifi.buttons.radius + border.width: (control.color === hifi.buttons.none || + (control.color === hifi.buttons.noneBorderless && control.hovered) || + (control.color === hifi.buttons.noneBorderlessWhite && control.hovered) || + (control.color === hifi.buttons.noneBorderlessGray && control.hovered)) ? 1 : 0; + border.color: control.color === hifi.buttons.noneBorderless ? hifi.colors.blueHighlight : + (control.color === hifi.buttons.noneBorderlessGray ? hifi.colors.baseGray : hifi.colors.white); - border.width: (control.color === hifi.buttons.none || - (control.color === hifi.buttons.noneBorderless && control.hovered) || - (control.color === hifi.buttons.noneBorderlessWhite && control.hovered) || - (control.color === hifi.buttons.noneBorderlessGray && control.hovered)) ? 1 : 0; - border.color: control.color === hifi.buttons.noneBorderless ? hifi.colors.blueHighlight : - (control.color === hifi.buttons.noneBorderlessGray ? hifi.colors.baseGray : hifi.colors.white); - - gradient: Gradient { - GradientStop { - position: 0.2 - color: { - if (!control.enabled) { - hifi.buttons.disabledColorStart[control.colorScheme] - } else if (control.pressed) { - hifi.buttons.pressedColor[control.color] - } else if (control.hovered) { - hifi.buttons.hoveredColor[control.color] + gradient: Gradient { + GradientStop { + position: 0.2 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorStart[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] } else if (!control.hovered && control.focus) { hifi.buttons.focusedColor[control.color] - } else { - hifi.buttons.colorStart[control.color] - } + } else { + hifi.buttons.colorStart[control.color] } } - GradientStop { - position: 1.0 - color: { - if (!control.enabled) { - hifi.buttons.disabledColorFinish[control.colorScheme] - } else if (control.pressed) { - hifi.buttons.pressedColor[control.color] - } else if (control.hovered) { - hifi.buttons.hoveredColor[control.color] + } + GradientStop { + position: 1.0 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorFinish[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] } else if (!control.hovered && control.focus) { hifi.buttons.focusedColor[control.color] - } else { - hifi.buttons.colorFinish[control.color] - } + } else { + hifi.buttons.colorFinish[control.color] } } } } - - label: Item { - HiFiGlyphs { - id: buttonGlyph; - visible: root.buttonGlyph !== ""; - text: root.buttonGlyph === "" ? hifi.glyphs.question : root.buttonGlyph; - // Size - size: 34; - // Anchors - anchors.right: buttonText.left; - anchors.top: parent.top; - anchors.bottom: parent.bottom; - // Style - color: enabled ? hifi.buttons.textColor[control.color] - : hifi.buttons.disabledTextColor[control.colorScheme]; - // Alignment - horizontalAlignment: Text.AlignHCenter; - verticalAlignment: Text.AlignVCenter; - } - RalewayBold { - id: buttonText; - anchors.centerIn: parent; - font.capitalization: Font.AllUppercase - color: enabled ? hifi.buttons.textColor[control.color] - : hifi.buttons.disabledTextColor[control.colorScheme] - size: hifi.fontSizes.buttonLabel - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: control.text - } - } + } + + contentItem: Item { + HiFiGlyphs { + id: buttonGlyph; + visible: control.buttonGlyph !== ""; + text: control.buttonGlyph === "" ? hifi.glyphs.question : control.buttonGlyph; + // Size + size: 34; + // Anchors + anchors.right: buttonText.left; + anchors.top: parent.top; + anchors.bottom: parent.bottom; + // Style + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme]; + // Alignment + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + } + RalewayBold { + id: buttonText; + anchors.centerIn: parent; + font.capitalization: Font.AllUppercase + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme] + size: hifi.fontSizes.buttonLabel + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + } } } + diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml index 973bbee60e..e13c9875e8 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -8,9 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick 2.2 +import QtQuick.Controls 2.2 as Original import "../styles-uit" @@ -28,85 +27,89 @@ Original.CheckBox { property bool wrap: true; readonly property int checkSize: Math.max(boxSize - 8, 10) readonly property int checkRadius: 2 - activeFocusOnPress: true + focusPolicy: Qt.ClickFocus + hoverEnabled: true onClicked: { Tablet.playSound(TabletEnums.ButtonClick); } -// TODO: doesnt works for QQC1. check with QQC2 -// onHovered: { -// Tablet.playSound(TabletEnums.ButtonHover); -// } - - style: CheckBoxStyle { - indicator: Rectangle { - id: box - implicitWidth: boxSize - implicitHeight: boxSize - radius: boxRadius - border.width: 1 - border.color: pressed || hovered - ? hifi.colors.checkboxCheckedBorder - : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) - - gradient: Gradient { - GradientStop { - position: 0.2 - color: pressed || hovered - ? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightStart) - : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart) - } - GradientStop { - position: 1.0 - color: pressed || hovered - ? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightFinish) - : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) - } - } - - Rectangle { - visible: pressed || hovered - anchors.centerIn: parent - id: innerBox - width: checkSize - 4 - height: width - radius: checkRadius - color: hifi.colors.checkboxCheckedBorder - } - - Rectangle { - id: check - width: checkSize - height: checkSize - radius: checkRadius - anchors.centerIn: parent - color: isRedCheck ? hifi.colors.checkboxCheckedRed : hifi.colors.checkboxChecked - border.width: 2 - border.color: isRedCheck? hifi.colors.checkboxCheckedBorderRed : hifi.colors.checkboxCheckedBorder - visible: checked && !pressed || !checked && pressed - } - - Rectangle { - id: disabledOverlay - visible: !enabled - width: boxSize - height: boxSize - radius: boxRadius - border.width: 1 - border.color: hifi.colors.baseGrayHighlight - color: hifi.colors.baseGrayHighlight - opacity: 0.5 - } - } - - label: Label { - text: checkBox.text - color: checkBox.color - x: 2 - wrapMode: checkBox.wrap ? Text.Wrap : Text.NoWrap - elide: checkBox.wrap ? Text.ElideNone : Text.ElideRight - enabled: checkBox.enabled + onHoveredChanged: { + if (hovered) { + Tablet.playSound(TabletEnums.ButtonHover); } } + + + indicator: Rectangle { + id: box + implicitWidth: boxSize + implicitHeight: boxSize + radius: boxRadius + y: parent.height / 2 - height / 2 + border.width: 1 + border.color: pressed || hovered + ? hifi.colors.checkboxCheckedBorder + : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) + + gradient: Gradient { + GradientStop { + position: 0.2 + color: pressed || hovered + ? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightStart) + : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart) + } + GradientStop { + position: 1.0 + color: pressed || hovered + ? (checkBox.isLightColorScheme ? hifi.colors.checkboxChecked : hifi.colors.checkboxLightFinish) + : (checkBox.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) + } + } + + Rectangle { + visible: pressed || hovered + anchors.centerIn: parent + id: innerBox + width: checkSize - 4 + height: width + radius: checkRadius + color: hifi.colors.checkboxCheckedBorder + } + + Rectangle { + id: check + width: checkSize + height: checkSize + radius: checkRadius + anchors.centerIn: parent + color: isRedCheck ? hifi.colors.checkboxCheckedRed : hifi.colors.checkboxChecked + border.width: 2 + border.color: isRedCheck? hifi.colors.checkboxCheckedBorderRed : hifi.colors.checkboxCheckedBorder + visible: checked && !pressed || !checked && pressed + } + + Rectangle { + id: disabledOverlay + visible: !enabled + width: boxSize + height: boxSize + radius: boxRadius + border.width: 1 + border.color: hifi.colors.baseGrayHighlight + color: hifi.colors.baseGrayHighlight + opacity: 0.5 + } + } + + contentItem: Label { + text: checkBox.text + color: checkBox.color + x: 2 + verticalAlignment: Text.AlignVCenter + wrapMode: checkBox.wrap ? Text.Wrap : Text.NoWrap + elide: checkBox.wrap ? Text.ElideNone : Text.ElideRight + enabled: checkBox.enabled + leftPadding: checkBox.indicator.width + checkBox.spacing + } } diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml index d672fa6387..ab8a6c2344 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -8,9 +8,8 @@ // 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 QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import "../styles-uit" import "../controls-uit" as HifiControls @@ -24,6 +23,7 @@ FocusScope { property alias comboBox: comboBox readonly property alias currentText: comboBox.currentText; property alias currentIndex: comboBox.currentIndex; + property int currentHighLightedIndex: comboBox.currentIndex; property int dropdownHeight: 480 property int colorScheme: hifi.colorSchemes.light @@ -40,196 +40,134 @@ FocusScope { implicitHeight: comboBox.height; focus: true - Rectangle { - id: background - gradient: Gradient { - GradientStop { - position: 0.2 - color: popup.visible - ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) - : (isLightColorScheme ? hifi.colors.dropDownLightStart : hifi.colors.dropDownDarkStart) - } - GradientStop { - position: 1.0 - color: popup.visible - ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) - : (isLightColorScheme ? hifi.colors.dropDownLightFinish : hifi.colors.dropDownDarkFinish) - } - } - anchors.fill: parent - } - - SystemPalette { id: palette } - ComboBox { id: comboBox anchors.fill: parent - visible: false - height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control. - } - - FiraSansSemiBold { - id: textField - anchors { - left: parent.left - leftMargin: hifi.dimensions.textPadding - right: dropIcon.left - verticalCenter: parent.verticalCenter - } - size: hifi.fontSizes.textFieldInput - text: comboBox.currentText - elide: Text.ElideRight - color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText ) - } - - Item { - id: dropIcon - anchors { right: parent.right; verticalCenter: parent.verticalCenter } - height: background.height - width: height - Rectangle { - width: 1 - height: parent.height - anchors.top: parent.top - anchors.left: parent.left - color: isLightColorScheme ? hifi.colors.faintGray : hifi.colors.baseGray - } - HiFiGlyphs { - anchors { - top: parent.top - topMargin: -11 - horizontalCenter: parent.horizontalCenter - } - size: hifi.dimensions.spinnerSize - text: hifi.glyphs.caratDn - color: controlHover.containsMouse || popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText) - } - } - - MouseArea { - id: controlHover hoverEnabled: true - anchors.fill: parent - onClicked: toggleList(); - } + visible: true + height: hifi.fontSizes.textFieldInput + 13 // Match height of TextField control. - function toggleList() { - if (popup.visible) { - hideList(); - } else { - showList(); - } - } - - function showList() { - var r; - if (isDesktop) { - r = desktop.mapFromItem(root, 0, 0, root.width, root.height); - } else { - r = mapFromItem(root, 0, 0, root.width, root.height); - } - var y = r.y + r.height; - var bottom = y + scrollView.height; - var height = isDesktop ? desktop.height : tabletRoot.height; - if (bottom > height) { - y -= bottom - height + 8; - } - scrollView.x = r.x; - scrollView.y = y; - popup.visible = true; - popup.forceActiveFocus(); - listView.currentIndex = root.currentIndex; - scrollView.hoverEnabled = true; - } - - function hideList() { - popup.visible = false; - scrollView.hoverEnabled = false; - root.accepted(); - } - - FocusScope { - id: popup - parent: isDesktop ? desktop : root - anchors.fill: parent - z: isDesktop ? desktop.zLevels.menu : 12 - visible: false - focus: true - - MouseArea { - anchors.fill: parent - onClicked: hideList(); - } - - function previousItem() { listView.currentIndex = (listView.currentIndex + listView.count - 1) % listView.count; } - function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; } - function selectCurrentItem() { root.currentIndex = listView.currentIndex; hideList(); } - function selectSpecificItem(index) { root.currentIndex = index; hideList(); } + function previousItem() { root.currentHighLightedIndex = (root.currentHighLightedIndex + comboBox.count - 1) % comboBox.count; } + function nextItem() { root.currentHighLightedIndex = (root.currentHighLightedIndex + comboBox.count + 1) % comboBox.count; } + function selectCurrentItem() { root.currentIndex = root.currentHighLightedIndex; close(); /*hideList();*/ } + function selectSpecificItem(index) { root.currentIndex = index; close();/*hideList();*/ } Keys.onUpPressed: previousItem(); Keys.onDownPressed: nextItem(); Keys.onSpacePressed: selectCurrentItem(); Keys.onRightPressed: selectCurrentItem(); Keys.onReturnPressed: selectCurrentItem(); - Keys.onEscapePressed: hideList(); - ScrollView { - id: scrollView - height: root.dropdownHeight + background: Rectangle { + gradient: Gradient { + GradientStop { + position: 0.2 + color: comboBox.popup.visible + ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) + : (isLightColorScheme ? hifi.colors.dropDownLightStart : hifi.colors.dropDownDarkStart) + } + GradientStop { + position: 1.0 + color: comboBox.popup.visible + ? (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) + : (isLightColorScheme ? hifi.colors.dropDownLightFinish : hifi.colors.dropDownDarkFinish) + } + } + } + + indicator: Item { + id: dropIcon + anchors { right: parent.right; verticalCenter: parent.verticalCenter } + height: root.height + width: height + Rectangle { + width: 1 + height: parent.height + anchors.top: parent.top + anchors.left: parent.left + color: isLightColorScheme ? hifi.colors.faintGray : hifi.colors.baseGray + } + HiFiGlyphs { + anchors { top: parent.top; topMargin: -11; horizontalCenter: parent.horizontalCenter } + size: hifi.dimensions.spinnerSize + text: hifi.glyphs.caratDn + color: comboBox.hovered || comboBox.popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText) + } + } + + contentItem: FiraSansSemiBold { + id: textField + anchors { + left: parent.left + leftMargin: hifi.dimensions.textPadding + verticalCenter: parent.verticalCenter + } + size: hifi.fontSizes.textFieldInput + text: comboBox.currentText + elide: Text.ElideRight + color: comboBox.hovered || comboBox.popup.visible ? hifi.colors.baseGray : (isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText ) + } + + delegate: ItemDelegate { + id: itemDelegate + hoverEnabled: true width: root.width + 4 - property bool hoverEnabled: false; + height: popupText.implicitHeight * 1.4 + highlighted: root.currentHighLightedIndex == index - style: ScrollViewStyle { - decrementControl: Item { - visible: false - } - incrementControl: Item { - visible: false - } - scrollBarBackground: Rectangle{ - implicitWidth: 20 - color: hifi.colors.baseGray - } - - handle: - Rectangle { - implicitWidth: 16 - anchors.left: parent.left - anchors.leftMargin: 3 - anchors.top: parent.top - anchors.bottom: parent.bottom - radius: 6 - color: hifi.colors.lightGrayText + onHoveredChanged: { + if (hovered) { + root.currentHighLightedIndex = index } } - ListView { + background: Rectangle { + color: itemDelegate.highlighted ? hifi.colors.primaryHighlight + : (isLightColorScheme ? hifi.colors.dropDownPressedLight + : hifi.colors.dropDownPressedDark) + } + + contentItem: FiraSansSemiBold { + id: popupText + anchors.left: parent.left + anchors.leftMargin: hifi.dimensions.textPadding + anchors.verticalCenter: parent.verticalCenter + text: comboBox.model[index] ? comboBox.model[index] + : (comboBox.model.get && comboBox.model.get(index).text ? + comboBox.model.get(index).text : "") + size: hifi.fontSizes.textFieldInput + color: hifi.colors.baseGray + } + } + popup: Popup { + y: comboBox.height - 1 + width: comboBox.width + implicitHeight: listView.contentHeight > dropdownHeight ? dropdownHeight + : listView.contentHeight + padding: 0 + topPadding: 1 + + onClosed: { + root.accepted() + } + + contentItem: ListView { id: listView - height: textField.height * count * 1.4 - model: root.model - delegate: Rectangle { - width: root.width + 4 - height: popupText.implicitHeight * 1.4 - color: (listView.currentIndex === index) ? hifi.colors.primaryHighlight : - (isLightColorScheme ? hifi.colors.dropDownPressedLight : hifi.colors.dropDownPressedDark) - FiraSansSemiBold { - anchors.left: parent.left - anchors.leftMargin: hifi.dimensions.textPadding - anchors.verticalCenter: parent.verticalCenter - id: popupText - text: listView.model[index] ? listView.model[index] : (listView.model.get && listView.model.get(index).text ? listView.model.get(index).text : "") - size: hifi.fontSizes.textFieldInput - color: hifi.colors.baseGray - } - MouseArea { - id: popupHover - anchors.fill: parent; - hoverEnabled: scrollView.hoverEnabled; - onEntered: listView.currentIndex = index; - onClicked: popup.selectSpecificItem(index); - } + clip: true + model: comboBox.popup.visible ? comboBox.delegateModel : null + currentIndex: root.currentHighLightedIndex + delegate: comboBox.delegate + ScrollBar.vertical: HifiControls.ScrollBar { + id: scrollbar + parent: listView + policy: ScrollBar.AsNeeded + visible: size < 1.0 } } + + background: Rectangle { + color: hifi.colors.baseGray + } } } diff --git a/interface/resources/qml/controls-uit/GlyphButton.qml b/interface/resources/qml/controls-uit/GlyphButton.qml index 024c131a09..9129486720 100644 --- a/interface/resources/qml/controls-uit/GlyphButton.qml +++ b/interface/resources/qml/controls-uit/GlyphButton.qml @@ -8,15 +8,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - -import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.2 as Original import TabletScriptingInterface 1.0 import "../styles-uit" Original.Button { + id: control property int color: 0 property int colorScheme: hifi.colorSchemes.light property string glyph: "" @@ -41,59 +40,52 @@ Original.Button { Tablet.playSound(TabletEnums.ButtonClick); } - style: ButtonStyle { + background: Rectangle { + radius: hifi.buttons.radius - background: Rectangle { - radius: hifi.buttons.radius - - gradient: Gradient { - GradientStop { - position: 0.2 - color: { - if (!control.enabled) { - hifi.buttons.disabledColorStart[control.colorScheme] - } else if (control.pressed) { - hifi.buttons.pressedColor[control.color] - } else if (control.hovered) { - hifi.buttons.hoveredColor[control.color] + gradient: Gradient { + GradientStop { + position: 0.2 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorStart[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] } else if (!control.hovered && control.focus) { hifi.buttons.focusedColor[control.color] - } else { - hifi.buttons.colorStart[control.color] - } - } - } - GradientStop { - position: 1.0 - color: { - if (!control.enabled) { - hifi.buttons.disabledColorFinish[control.colorScheme] - } else if (control.pressed) { - hifi.buttons.pressedColor[control.color] - } else if (control.hovered) { - hifi.buttons.hoveredColor[control.color] - } else if (!control.hovered && control.focus) { - hifi.buttons.focusedColor[control.color] - } else { - hifi.buttons.colorFinish[control.color] - } + } else { + hifi.buttons.colorStart[control.color] } } } - } - - label: HiFiGlyphs { - color: enabled ? hifi.buttons.textColor[control.color] - : hifi.buttons.disabledTextColor[control.colorScheme] - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - anchors { - // Tweak horizontal alignment so that it looks right. - left: parent.left - leftMargin: -0.5 + GradientStop { + position: 1.0 + color: { + if (!control.enabled) { + hifi.buttons.disabledColorFinish[control.colorScheme] + } else if (control.pressed) { + hifi.buttons.pressedColor[control.color] + } else if (control.hovered) { + hifi.buttons.hoveredColor[control.color] + } else if (!control.hovered && control.focus) { + hifi.buttons.focusedColor[control.color] + } else { + hifi.buttons.colorFinish[control.color] + } + } } - text: control.glyph - size: control.size } } + + contentItem: HiFiGlyphs { + color: enabled ? hifi.buttons.textColor[control.color] + : hifi.buttons.disabledTextColor[control.colorScheme] + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.glyph + size: control.size + } } + diff --git a/interface/resources/qml/controls-uit/HorizontalRule.qml b/interface/resources/qml/controls-uit/HorizontalRule.qml index 425500f1d4..0609cc451d 100644 --- a/interface/resources/qml/controls-uit/HorizontalRule.qml +++ b/interface/resources/qml/controls-uit/HorizontalRule.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 Rectangle { anchors.left: parent.left diff --git a/interface/resources/qml/controls-uit/ImageMessageBox.qml b/interface/resources/qml/controls-uit/ImageMessageBox.qml index 95c753aab4..74313f7ffe 100644 --- a/interface/resources/qml/controls-uit/ImageMessageBox.qml +++ b/interface/resources/qml/controls-uit/ImageMessageBox.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../styles-uit" Item { diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index ea76d44aaa..9d4fd33022 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -26,15 +26,17 @@ Rectangle { readonly property int keyboardRowHeight: 50 readonly property int keyboardWidth: 480 + readonly property int keyboardHeight: 200 readonly property int mirrorTextHeight: keyboardRowHeight property bool password: false property alias mirroredText: mirrorText.text property bool showMirrorText: true - readonly property int raisedHeight: 200 - height: enabled && raised ? raisedHeight + (showMirrorText ? keyboardRowHeight : 0) : 0 + readonly property int raisedHeight: keyboardHeight + (showMirrorText ? keyboardRowHeight : 0) + + height: enabled && raised ? raisedHeight : 0 visible: enabled && raised property bool shiftMode: false @@ -158,7 +160,7 @@ Rectangle { id: keyboardRect y: showMirrorText ? mirrorTextHeight : 0 width: keyboardWidth - height: raisedHeight + height: keyboardHeight color: "#252525" anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom @@ -167,7 +169,7 @@ Rectangle { Column { id: columnAlpha width: keyboardWidth - height: raisedHeight + height: keyboardHeight visible: !numeric Row { @@ -259,7 +261,7 @@ Rectangle { Column { id: columnNumeric width: keyboardWidth - height: raisedHeight + height: keyboardHeight visible: numeric Row { diff --git a/interface/resources/qml/controls-uit/Label.qml b/interface/resources/qml/controls-uit/Label.qml index 1dc3aa0dd4..4c7051b495 100644 --- a/interface/resources/qml/controls-uit/Label.qml +++ b/interface/resources/qml/controls-uit/Label.qml @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 +import QtQuick 2.7 import "../styles-uit" diff --git a/interface/resources/qml/controls-uit/QueuedButton.qml b/interface/resources/qml/controls-uit/QueuedButton.qml index 36ffbe582f..6612d582df 100644 --- a/interface/resources/qml/controls-uit/QueuedButton.qml +++ b/interface/resources/qml/controls-uit/QueuedButton.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 import "../styles-uit" import "." as HifiControls diff --git a/interface/resources/qml/controls-uit/RadioButton.qml b/interface/resources/qml/controls-uit/RadioButton.qml index a818be072b..ebfe1ff9a9 100644 --- a/interface/resources/qml/controls-uit/RadioButton.qml +++ b/interface/resources/qml/controls-uit/RadioButton.qml @@ -9,8 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.2 as Original import "../styles-uit" import "../controls-uit" as HifiControls @@ -21,6 +20,8 @@ Original.RadioButton { id: radioButton HifiConstants { id: hifi } + hoverEnabled: true + property int colorScheme: hifi.colorSchemes.light readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light @@ -33,50 +34,53 @@ Original.RadioButton { Tablet.playSound(TabletEnums.ButtonClick); } -// TODO: doesnt works for QQC1. check with QQC2 -// onHovered: { -// Tablet.playSound(TabletEnums.ButtonHover); -// } - - style: RadioButtonStyle { - indicator: Rectangle { - id: box - width: boxSize - height: boxSize - radius: 7 - gradient: Gradient { - GradientStop { - position: 0.2 - color: pressed || hovered - ? (radioButton.isLightColorScheme ? hifi.colors.checkboxDarkStart : hifi.colors.checkboxLightStart) - : (radioButton.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart) - } - GradientStop { - position: 1.0 - color: pressed || hovered - ? (radioButton.isLightColorScheme ? hifi.colors.checkboxDarkFinish : hifi.colors.checkboxLightFinish) - : (radioButton.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) - } - } - - Rectangle { - id: check - width: checkSize - height: checkSize - radius: 7 - anchors.centerIn: parent - color: "#00B4EF" - border.width: 1 - border.color: "#36CDFF" - visible: checked && !pressed || !checked && pressed - } - } - - label: RalewaySemiBold { - text: control.text - size: hifi.fontSizes.inputLabel - color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText - x: radioButton.boxSize / 2 + onHoveredChanged: { + if (hovered) { + Tablet.playSound(TabletEnums.ButtonHover); } } + + indicator: Rectangle { + id: box + width: boxSize + height: boxSize + radius: 7 + x: radioButton.leftPadding + y: parent.height / 2 - height / 2 + gradient: Gradient { + GradientStop { + position: 0.2 + color: pressed || hovered + ? (radioButton.isLightColorScheme ? hifi.colors.checkboxDarkStart : hifi.colors.checkboxLightStart) + : (radioButton.isLightColorScheme ? hifi.colors.checkboxLightStart : hifi.colors.checkboxDarkStart) + } + GradientStop { + position: 1.0 + color: pressed || hovered + ? (radioButton.isLightColorScheme ? hifi.colors.checkboxDarkFinish : hifi.colors.checkboxLightFinish) + : (radioButton.isLightColorScheme ? hifi.colors.checkboxLightFinish : hifi.colors.checkboxDarkFinish) + } + } + + Rectangle { + id: check + width: checkSize + height: checkSize + radius: 7 + anchors.centerIn: parent + color: "#00B4EF" + border.width: 1 + border.color: "#36CDFF" + visible: checked && !pressed || !checked && pressed + } + } + + contentItem: RalewaySemiBold { + text: radioButton.text + size: hifi.fontSizes.inputLabel + color: isLightColorScheme ? hifi.colors.lightGray : hifi.colors.lightGrayText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + leftPadding: radioButton.indicator.width + radioButton.spacing + } } diff --git a/interface/resources/qml/controls-uit/ScrollBar.qml b/interface/resources/qml/controls-uit/ScrollBar.qml new file mode 100644 index 0000000000..125e84e585 --- /dev/null +++ b/interface/resources/qml/controls-uit/ScrollBar.qml @@ -0,0 +1,41 @@ +// +// ScrollBar.qml +// +// Created by Vlad Stelmahovsky on 27 Nov 2017 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import QtQuick.Controls 2.2 + +import "../styles-uit" + +ScrollBar { + visible: size < 1.0 + + HifiConstants { id: hifi } + property int colorScheme: hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + + background: Item { + implicitWidth: hifi.dimensions.scrollbarBackgroundWidth + Rectangle { + anchors { fill: parent; topMargin: 3; bottomMargin: 3 } + radius: hifi.dimensions.scrollbarHandleWidth/2 + color: isLightColorScheme ? hifi.colors.tableScrollBackgroundLight + : hifi.colors.tableScrollBackgroundDark + } + } + + contentItem: Item { + implicitWidth: hifi.dimensions.scrollbarHandleWidth + Rectangle { + anchors { fill: parent; topMargin: 1; bottomMargin: 1 } + radius: hifi.dimensions.scrollbarHandleWidth/2 + color: isLightColorScheme ? hifi.colors.tableScrollHandleLight : hifi.colors.tableScrollHandleDark + } + } +} diff --git a/interface/resources/qml/controls-uit/Slider.qml b/interface/resources/qml/controls-uit/Slider.qml index 89bae9bcde..3726d3f260 100644 --- a/interface/resources/qml/controls-uit/Slider.qml +++ b/interface/resources/qml/controls-uit/Slider.qml @@ -8,9 +8,8 @@ // 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 QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import "../styles-uit" import "../controls-uit" as HifiControls @@ -23,66 +22,65 @@ Slider { property string label: "" property real controlHeight: height + (sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0) + property alias minimumValue: slider.from + property alias maximumValue: slider.to + height: hifi.fontSizes.textFieldInput + 14 // Match height of TextField control. y: sliderLabel.visible ? sliderLabel.height + sliderLabel.anchors.bottomMargin : 0 - style: SliderStyle { + background: Rectangle { + x: slider.leftPadding + y: slider.topPadding + slider.availableHeight / 2 - height / 2 - groove: Rectangle { - implicitWidth: 50 - implicitHeight: hifi.dimensions.sliderGrooveHeight + implicitWidth: 50 + implicitHeight: hifi.dimensions.sliderGrooveHeight + width: slider.availableWidth + height: implicitHeight + radius: height / 2 + color: isLightColorScheme ? hifi.colors.sliderGutterLight : hifi.colors.sliderGutterDark + + Rectangle { + width: slider.visualPosition * parent.width + height: parent.height radius: height / 2 - color: isLightColorScheme ? hifi.colors.sliderGutterLight : hifi.colors.sliderGutterDark + gradient: Gradient { + GradientStop { position: 0.0; color: hifi.colors.blueAccent } + GradientStop { position: 1.0; color: hifi.colors.primaryHighlight } + } + } + } - Rectangle { - width: parent.height - 2 - height: slider.width * (slider.value - slider.minimumValue) / (slider.maximumValue - slider.minimumValue) - 1 - radius: height / 2 - anchors { - top: parent.top - topMargin: width + 1 - left: parent.left - leftMargin: 1 - } - transformOrigin: Item.TopLeft - rotation: -90 - gradient: Gradient { - GradientStop { position: 0.0; color: hifi.colors.blueAccent } - GradientStop { position: 1.0; color: hifi.colors.primaryHighlight } - } + handle: Rectangle { + x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width) + y: slider.topPadding + slider.availableHeight / 2 - height / 2 + implicitWidth: hifi.dimensions.sliderHandleSize + implicitHeight: hifi.dimensions.sliderHandleSize + radius: height / 2 + border.width: 1 + border.color: isLightColorScheme ? hifi.colors.sliderBorderLight : hifi.colors.sliderBorderDark + gradient: Gradient { + GradientStop { + position: 0.0 + color: pressed || hovered + ? (isLightColorScheme ? hifi.colors.sliderDarkStart : hifi.colors.sliderLightStart ) + : (isLightColorScheme ? hifi.colors.sliderLightStart : hifi.colors.sliderDarkStart ) + } + GradientStop { + position: 1.0 + color: pressed || hovered + ? (isLightColorScheme ? hifi.colors.sliderDarkFinish : hifi.colors.sliderLightFinish ) + : (isLightColorScheme ? hifi.colors.sliderLightFinish : hifi.colors.sliderDarkFinish ) } } - handle: Rectangle { - implicitWidth: hifi.dimensions.sliderHandleSize - implicitHeight: hifi.dimensions.sliderHandleSize + Rectangle { + height: parent.height - 2 + width: height radius: height / 2 + anchors.centerIn: parent + color: hifi.colors.transparent border.width: 1 - border.color: isLightColorScheme ? hifi.colors.sliderBorderLight : hifi.colors.sliderBorderDark - gradient: Gradient { - GradientStop { - position: 0.0 - color: pressed || hovered - ? (isLightColorScheme ? hifi.colors.sliderDarkStart : hifi.colors.sliderLightStart ) - : (isLightColorScheme ? hifi.colors.sliderLightStart : hifi.colors.sliderDarkStart ) - } - GradientStop { - position: 1.0 - color: pressed || hovered - ? (isLightColorScheme ? hifi.colors.sliderDarkFinish : hifi.colors.sliderLightFinish ) - : (isLightColorScheme ? hifi.colors.sliderLightFinish : hifi.colors.sliderDarkFinish ) - } - } - - Rectangle { - height: parent.height - 2 - width: height - radius: height / 2 - anchors.centerIn: parent - color: hifi.colors.transparent - border.width: 1 - border.color: hifi.colors.black - } + border.color: hifi.colors.black } } diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index 30f6682d5a..83c30ce162 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -8,9 +8,8 @@ // 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 QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import "../styles-uit" import "../controls-uit" as HifiControls @@ -19,11 +18,40 @@ SpinBox { id: spinBox property int colorScheme: hifi.colorSchemes.light - readonly property bool isLightColorScheme: colorScheme == hifi.colorSchemes.light + readonly property bool isLightColorScheme: colorScheme === hifi.colorSchemes.light property string label: "" property string labelInside: "" property color colorLabelInside: hifi.colors.white property real controlHeight: height + (spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0) + property int decimals: 2; + property real factor: Math.pow(10, decimals) + + property real minimumValue: 0.0 + property real maximumValue: 0.0 + + property real realValue: 0.0 + property real realFrom: 0.0 + property real realTo: 100.0 + property real realStepSize: 1.0 + + implicitHeight: height + implicitWidth: width + + padding: 0 + leftPadding: 0 + rightPadding: padding + (up.indicator ? up.indicator.width : 0) + topPadding: 0 + bottomPadding: 0 + + locale: Qt.locale("en_US") + + onValueModified: realValue = value/factor + onValueChanged: realValue = value/factor + + stepSize: realStepSize*factor + value: realValue*factor + to : realTo*factor + from : realFrom*factor font.family: "Fira Sans SemiBold" font.pixelSize: hifi.fontSizes.textFieldInput @@ -31,43 +59,67 @@ SpinBox { y: spinBoxLabel.visible ? spinBoxLabel.height + spinBoxLabel.anchors.bottomMargin : 0 - style: SpinBoxStyle { - id: spinStyle - background: Rectangle { - color: isLightColorScheme - ? (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGray) - : (spinBox.activeFocus ? hifi.colors.black : hifi.colors.baseGrayShadow) - border.color: spinBoxLabelInside.visible ? spinBoxLabelInside.color : hifi.colors.primaryHighlight - border.width: spinBox.activeFocus ? spinBoxLabelInside.visible ? 2 : 1 : 0 - } + background: Rectangle { + color: isLightColorScheme + ? (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGray) + : (spinBox.activeFocus ? hifi.colors.black : hifi.colors.baseGrayShadow) + border.color: spinBoxLabelInside.visible ? spinBoxLabelInside.color : hifi.colors.primaryHighlight + border.width: spinBox.activeFocus ? spinBoxLabelInside.visible ? 2 : 1 : 0 + } - textColor: isLightColorScheme - ? (spinBox.activeFocus ? hifi.colors.black : hifi.colors.lightGray) - : (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGrayText) + validator: DoubleValidator { + bottom: Math.min(spinBox.from, spinBox.to)*spinBox.factor + top: Math.max(spinBox.from, spinBox.to)*spinBox.factor + } + + textFromValue: function(value, locale) { + return parseFloat(value*1.0/factor).toFixed(decimals); + } + + valueFromText: function(text, locale) { + return Number.fromLocaleString(locale, text); + } + + + contentItem: TextInput { + z: 2 + color: isLightColorScheme + ? (spinBox.activeFocus ? hifi.colors.black : hifi.colors.lightGray) + : (spinBox.activeFocus ? hifi.colors.white : hifi.colors.lightGrayText) selectedTextColor: hifi.colors.black selectionColor: hifi.colors.primaryHighlight - - horizontalAlignment: Qt.AlignLeft - padding.left: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding - padding.right: hifi.dimensions.spinnerSize - padding.top: 0 - - incrementControl: HiFiGlyphs { - id: incrementButton + text: spinBox.textFromValue(spinBox.value, spinBox.locale) + verticalAlignment: Qt.AlignVCenter + leftPadding: spinBoxLabelInside.visible ? 30 : hifi.dimensions.textPadding + //rightPadding: hifi.dimensions.spinnerSize + width: spinBox.width - hifi.dimensions.spinnerSize + } + up.indicator: Item { + x: spinBox.width - implicitWidth - 5 + y: 1 + clip: true + implicitHeight: spinBox.implicitHeight/2 + implicitWidth: spinBox.implicitHeight/2 + HiFiGlyphs { + anchors.centerIn: parent text: hifi.glyphs.caratUp - x: 10 - y: 1 size: hifi.dimensions.spinnerSize - color: styleData.upPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray + color: spinBox.down.pressed || spinBox.up.hovered ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray } + } - decrementControl: HiFiGlyphs { - text: hifi.glyphs.caratDn - x: 10 - y: -1 - size: hifi.dimensions.spinnerSize - color: styleData.downPressed ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray - } + down.indicator: Item { + x: spinBox.width - implicitWidth - 5 + y: spinBox.implicitHeight/2 + clip: true + implicitHeight: spinBox.implicitHeight/2 + implicitWidth: spinBox.implicitHeight/2 + HiFiGlyphs { + anchors.centerIn: parent + text: hifi.glyphs.caratDn + size: hifi.dimensions.spinnerSize + color: spinBox.down.pressed || spinBox.down.hovered ? (isLightColorScheme ? hifi.colors.black : hifi.colors.white) : hifi.colors.gray + } } HifiControls.Label { @@ -91,26 +143,26 @@ SpinBox { visible: spinBox.labelInside != "" } - MouseArea { - anchors.fill: parent - propagateComposedEvents: true - onWheel: { - if(spinBox.activeFocus) - wheel.accepted = false - else - wheel.accepted = true - } - onPressed: { - mouse.accepted = false - } - onReleased: { - mouse.accepted = false - } - onClicked: { - mouse.accepted = false - } - onDoubleClicked: { - mouse.accepted = false - } - } +// MouseArea { +// anchors.fill: parent +// propagateComposedEvents: true +// onWheel: { +// if(spinBox.activeFocus) +// wheel.accepted = false +// else +// wheel.accepted = true +// } +// onPressed: { +// mouse.accepted = false +// } +// onReleased: { +// mouse.accepted = false +// } +// onClicked: { +// mouse.accepted = false +// } +// onDoubleClicked: { +// mouse.accepted = false +// } +// } } diff --git a/interface/resources/qml/controls-uit/Switch.qml b/interface/resources/qml/controls-uit/Switch.qml index d54f986717..bfe86b1420 100644 --- a/interface/resources/qml/controls-uit/Switch.qml +++ b/interface/resources/qml/controls-uit/Switch.qml @@ -8,9 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.2 as Original import "../styles-uit" @@ -33,44 +32,49 @@ Item { Original.Switch { id: originalSwitch; - activeFocusOnPress: true; + focusPolicy: Qt.ClickFocus anchors.top: rootSwitch.top; anchors.left: rootSwitch.left; anchors.leftMargin: rootSwitch.width/2 - rootSwitch.switchWidth/2; onCheckedChanged: rootSwitch.onCheckedChanged(); onClicked: rootSwitch.clicked(); + hoverEnabled: true - style: SwitchStyle { + topPadding: 3; + leftPadding: 3; + rightPadding: 3; + bottomPadding: 3; - padding { - top: 3; - left: 3; - right: 3; - bottom: 3; + onHoveredChanged: { + if (hovered) { + switchHandle.color = hifi.colors.blueHighlight; + } else { + switchHandle.color = hifi.colors.lightGray; + } + } + + background: Rectangle { + color: "#252525"; + implicitWidth: rootSwitch.switchWidth; + implicitHeight: rootSwitch.height; + radius: rootSwitch.switchRadius; + } + + indicator: Rectangle { + id: switchHandle; + implicitWidth: rootSwitch.height - originalSwitch.topPadding - originalSwitch.bottomPadding; + implicitHeight: implicitWidth; + radius: implicitWidth/2; + border.color: hifi.colors.lightGrayText; + color: hifi.colors.lightGray; + //x: originalSwitch.leftPadding + x: Math.max(0, Math.min(parent.width - width, originalSwitch.visualPosition * parent.width - (width / 2))) + y: parent.height / 2 - height / 2 + Behavior on x { + enabled: !originalSwitch.down + SmoothedAnimation { velocity: 200 } } - groove: Rectangle { - color: "#252525"; - implicitWidth: rootSwitch.switchWidth; - implicitHeight: rootSwitch.height; - radius: rootSwitch.switchRadius; - } - - handle: Rectangle { - id: switchHandle; - implicitWidth: rootSwitch.height - padding.top - padding.bottom; - implicitHeight: implicitWidth; - radius: implicitWidth/2; - border.color: hifi.colors.lightGrayText; - color: hifi.colors.lightGray; - - MouseArea { - anchors.fill: parent; - hoverEnabled: true; - onEntered: parent.color = hifi.colors.blueHighlight; - onExited: parent.color = hifi.colors.lightGray; - } - } } } diff --git a/interface/resources/qml/controls-uit/Table.qml b/interface/resources/qml/controls-uit/Table.qml index 3c1d0fcd3c..ce4e1c376a 100644 --- a/interface/resources/qml/controls-uit/Table.qml +++ b/interface/resources/qml/controls-uit/Table.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import QtQuick.Controls 2.2 as QQC2 +import QtQuick.Controls 2.3 as QQC2 import "../styles-uit" diff --git a/interface/resources/qml/controls-uit/TabletHeader.qml b/interface/resources/qml/controls-uit/TabletHeader.qml index 17530f81ea..56203de286 100644 --- a/interface/resources/qml/controls-uit/TabletHeader.qml +++ b/interface/resources/qml/controls-uit/TabletHeader.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../styles-uit" diff --git a/interface/resources/qml/controls-uit/TextAction.qml b/interface/resources/qml/controls-uit/TextAction.qml index 1c66c3630a..1745a6c273 100644 --- a/interface/resources/qml/controls-uit/TextAction.qml +++ b/interface/resources/qml/controls-uit/TextAction.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "../styles-uit" import "../controls-uit" as HifiControls diff --git a/interface/resources/qml/controls-uit/TextEdit.qml b/interface/resources/qml/controls-uit/TextEdit.qml index 0fe03150f4..a72a3b13d8 100644 --- a/interface/resources/qml/controls-uit/TextEdit.qml +++ b/interface/resources/qml/controls-uit/TextEdit.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "../styles-uit" TextEdit { diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml index 6743d08275..3fcdf30d2d 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -8,9 +8,8 @@ // 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 QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import "../styles-uit" import "../controls-uit" as HifiControls @@ -29,11 +28,17 @@ TextField { property int roundedBorderRadius: 4 property bool error: false; property bool hasClearButton: false; + property alias textColor: textField.color property string leftPermanentGlyph: ""; property string centerPlaceholderGlyph: ""; placeholderText: textField.placeholderText + property bool rightAnchorSet: false; + anchors.onRightChanged: { + rightAnchorSet = true; + } + font.family: "Fira Sans" font.pixelSize: hifi.fontSizes.textFieldInput height: implicitHeight + 3 // Make surrounding box higher so that highlight is vertically centered. @@ -44,42 +49,56 @@ TextField { // workaround for https://bugreports.qt.io/browse/QTBUG-49297 Keys.onPressed: { switch (event.key) { - case Qt.Key_Return: - case Qt.Key_Enter: - event.accepted = true; + case Qt.Key_Return: + case Qt.Key_Enter: + event.accepted = true; - // emit accepted signal manually - if (acceptableInput) { - accepted(); - } + // emit accepted signal manually + if (acceptableInput) { + accepted(); + } } } - style: TextFieldStyle { - id: style; - textColor: { - if (isLightColorScheme) { - if (textField.activeFocus) { - hifi.colors.black - } else { - hifi.colors.lightGray - } - } else if (isFaintGrayColorScheme) { - if (textField.activeFocus) { - hifi.colors.black - } else { - hifi.colors.lightGray - } + Text { + id: placeholder + x: textField.leftPadding + y: textField.topPadding + width: textField.width - (textField.leftPadding + textField.rightPadding) + height: textField.height - (textField.topPadding + textField.bottomPadding) + + text: textField.placeholderText + font: textField.font + color: textField.placeholderTextColor + verticalAlignment: textField.verticalAlignment + visible: !textField.length && !textField.preeditText && (!textField.activeFocus || textField.horizontalAlignment !== Qt.AlignHCenter) + elide: Text.ElideRight + } + + color: { + if (isLightColorScheme) { + if (textField.activeFocus) { + hifi.colors.black } else { - if (textField.activeFocus) { - hifi.colors.white - } else { - hifi.colors.lightGrayText - } + hifi.colors.lightGray + } + } else if (isFaintGrayColorScheme) { + if (textField.activeFocus) { + hifi.colors.black + } else { + hifi.colors.lightGray + } + } else { + if (textField.activeFocus) { + hifi.colors.white + } else { + hifi.colors.lightGrayText } } - background: Rectangle { - color: { + } + + background: Rectangle { + color: { if (isLightColorScheme) { if (textField.activeFocus) { hifi.colors.white @@ -100,22 +119,22 @@ TextField { } } } - border.color: textField.error ? hifi.colors.redHighlight : + border.color: textField.error ? hifi.colors.redHighlight : (textField.activeFocus ? hifi.colors.primaryHighlight : (hasDefocusedBorder ? (isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray) : color)) - border.width: textField.activeFocus || hasRoundedBorder || textField.error ? 1 : 0 + border.width: textField.activeFocus || hasRoundedBorder || textField.error ? 1 : 0 radius: isSearchField ? textField.height / 2 : (hasRoundedBorder ? roundedBorderRadius : 0) - HiFiGlyphs { + HiFiGlyphs { text: textField.leftPermanentGlyph; - color: textColor; - size: hifi.fontSizes.textFieldSearchIcon; - anchors.left: parent.left; - anchors.verticalCenter: parent.verticalCenter; - anchors.leftMargin: hifi.dimensions.textPadding - 2; - visible: text; - } + color: textColor; + size: hifi.fontSizes.textFieldSearchIcon; + anchors.left: parent.left; + anchors.verticalCenter: parent.verticalCenter; + anchors.leftMargin: hifi.dimensions.textPadding - 2; + visible: text; + } - HiFiGlyphs { + HiFiGlyphs { text: textField.centerPlaceholderGlyph; color: textColor; size: parent.height; @@ -125,39 +144,40 @@ TextField { } HiFiGlyphs { - text: hifi.glyphs.search - color: textColor - size: hifi.fontSizes.textFieldSearchIcon - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: hifi.dimensions.textPadding - 2 - visible: isSearchField - } + text: hifi.glyphs.search + color: textColor + size: hifi.fontSizes.textFieldSearchIcon + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: hifi.dimensions.textPadding - 2 + visible: isSearchField + } - HiFiGlyphs { - text: hifi.glyphs.error - color: textColor - size: 40 - anchors.right: parent.right - anchors.rightMargin: hifi.dimensions.textPadding - 2 - anchors.verticalCenter: parent.verticalCenter - visible: hasClearButton && textField.text !== ""; + HiFiGlyphs { + text: hifi.glyphs.error + color: textColor + size: 40 + anchors.right: parent.right + anchors.rightMargin: hifi.dimensions.textPadding - 2 + anchors.verticalCenter: parent.verticalCenter + visible: hasClearButton && textField.text !== ""; - MouseArea { - anchors.fill: parent; - onClicked: { - textField.text = ""; - } + MouseArea { + anchors.fill: parent; + onClicked: { + textField.text = ""; } } } - placeholderTextColor: isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray - selectedTextColor: hifi.colors.black - selectionColor: hifi.colors.primaryHighlight - padding.left: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding - padding.right: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding } + property color placeholderTextColor: isFaintGrayColorScheme ? hifi.colors.lightGrayText : hifi.colors.lightGray + selectedTextColor: hifi.colors.black + selectionColor: hifi.colors.primaryHighlight + leftPadding: hasRoundedBorder ? textField.height / 2 : ((isSearchField || textField.leftPermanentGlyph !== "") ? textField.height - 2 : 0) + hifi.dimensions.textPadding + rightPadding: (hasClearButton ? textField.height - 2 : 0) + hifi.dimensions.textPadding + + HifiControls.Label { id: textFieldLabel text: textField.label @@ -165,11 +185,11 @@ TextField { anchors.left: parent.left Binding on anchors.right { - when: parent.right - value: parent.right + when: rightAnchorSet + value: textField.right } Binding on wrapMode { - when: parent.right + when: rightAnchorSet value: Text.WordWrap } diff --git a/interface/resources/qml/controls-uit/WebGlyphButton.qml b/interface/resources/qml/controls-uit/WebGlyphButton.qml index 15524e4188..fd7cd001b2 100644 --- a/interface/resources/qml/controls-uit/WebGlyphButton.qml +++ b/interface/resources/qml/controls-uit/WebGlyphButton.qml @@ -9,8 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.2 as Original import "../styles-uit" @@ -26,23 +25,16 @@ Original.Button { readonly property color clickedColor: "#FFFFFF" readonly property color disabledColor: "#575757" - style: ButtonStyle { - background: Item {} + background: Item {} - - label: HiFiGlyphs { - color: control.enabled ? (control.pressed ? control.clickedColor : - (control.hovered ? control.hoverColor : control.normalColor)) : - control.disabledColor - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - anchors { - // Tweak horizontal alignment so that it looks right. - left: parent.left - leftMargin: -0.5 - } - text: control.glyph - size: control.size - } + contentItem: HiFiGlyphs { + color: control.enabled ? (control.pressed ? control.clickedColor : + (control.hovered ? control.hoverColor : control.normalColor)) : + control.disabledColor + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.glyph + size: control.size } } + diff --git a/interface/resources/qml/controls/Button.qml b/interface/resources/qml/controls/Button.qml index c5a9f99343..6cbdec5644 100644 --- a/interface/resources/qml/controls/Button.qml +++ b/interface/resources/qml/controls/Button.qml @@ -1,27 +1,35 @@ import QtQuick 2.3 -import QtQuick.Controls 1.3 as Original -import QtQuick.Controls.Styles 1.3 +import QtQuick.Controls 2.2 as Original import "." import "../styles" +import "../controls-uit" Original.Button { - style: ButtonStyle { - HifiConstants { id: hifi } - padding { - top: 8 - left: 12 - right: 12 - bottom: 8 - } - background: Border { - anchors.fill: parent - } - label: Text { - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - text: control.text - color: control.enabled ? hifi.colors.text : hifi.colors.disabledText + id: control + + HifiConstants { id: hifi } + property Action action: null + + onActionChanged: { + if (action !== null && action.text !== "") { + control.text = action.text } } + + padding { + top: 8 + left: 12 + right: 12 + bottom: 8 + } + background: Border { + anchors.fill: parent + } + contentItem: Text { + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + text: control.text + color: control.enabled ? hifi.colors.text : hifi.colors.disabledText + } } diff --git a/interface/resources/qml/controls/FontAwesome.qml b/interface/resources/qml/controls/FontAwesome.qml index 2c897b6347..213a4b62f2 100644 --- a/interface/resources/qml/controls/FontAwesome.qml +++ b/interface/resources/qml/controls/FontAwesome.qml @@ -1,6 +1,4 @@ import QtQuick 2.3 -import QtQuick.Controls 1.3 -import QtQuick.Controls.Styles 1.3 Text { id: root diff --git a/interface/resources/qml/desktop/+android/Desktop.qml b/interface/resources/qml/desktop/+android/Desktop.qml new file mode 100644 index 0000000000..6a68f63d0a --- /dev/null +++ b/interface/resources/qml/desktop/+android/Desktop.qml @@ -0,0 +1,575 @@ +// +// Desktop.qml +// +// Created by Bradley Austin Davis on 15 Apr 2015 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import QtQuick.Controls 1.4 + +import "../dialogs" +import "../js/Utils.js" as Utils + +// This is our primary 'desktop' object to which all VR dialogs and windows are childed. +FocusScope { + id: desktop + objectName: "desktop" + anchors.fill: parent + + readonly property int invalid_position: -9999; + property rect recommendedRect: Qt.rect(0,0,0,0); + property var expectedChildren; + property bool repositionLocked: true + property bool hmdHandMouseActive: false + + onRepositionLockedChanged: { + if (!repositionLocked) { + d.handleSizeChanged(); + } + + } + + onHeightChanged: d.handleSizeChanged(); + + onWidthChanged: d.handleSizeChanged(); + + // Controls and windows can trigger this signal to ensure the desktop becomes visible + // when they're opened. + signal showDesktop(); + + // This is for JS/QML communication, which is unused in the Desktop, + // but not having this here results in spurious warnings about a + // missing signal + signal sendToScript(var message); + + // Allows QML/JS to find the desktop through the parent chain + property bool desktopRoot: true + + // The VR version of the primary menu + property var rootMenu: Menu { + id: rootMenuId + objectName: "rootMenu" + + property var exclusionGroups: ({}); + property Component exclusiveGroupMaker: Component { + ExclusiveGroup { + } + } + + function addExclusionGroup(qmlAction, exclusionGroup) { + + var exclusionGroupId = exclusionGroup.toString(); + if(!exclusionGroups[exclusionGroupId]) { + exclusionGroups[exclusionGroupId] = exclusiveGroupMaker.createObject(rootMenuId); + } + + qmlAction.exclusiveGroup = exclusionGroups[exclusionGroupId] + } + } + + // FIXME: Alpha gradients display as fuschia under QtQuick 2.5 on OSX/AMD + // because shaders are 4.2, and do not include #version declarations. + property bool gradientsSupported: Qt.platform.os != "osx" && !~GL.vendor.indexOf("ATI") + + readonly property alias zLevels: zLevels + QtObject { + id: zLevels; + readonly property real normal: 1 // make windows always appear higher than QML overlays and other non-window controls. + readonly property real top: 2000 + readonly property real modal: 4000 + readonly property real menu: 8000 + } + + QtObject { + id: d + + function handleSizeChanged() { + if (desktop.repositionLocked) { + return; + } + var oldRecommendedRect = recommendedRect; + var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect(); + var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y, + newRecommendedRectJS.width, + newRecommendedRectJS.height); + + var oldChildren = expectedChildren; + var newChildren = d.getRepositionChildren(); + if (oldRecommendedRect != Qt.rect(0,0,0,0) && oldRecommendedRect != Qt.rect(0,0,1,1) + && (oldRecommendedRect != newRecommendedRect + || oldChildren != newChildren) + ) { + expectedChildren = newChildren; + d.repositionAll(); + } + recommendedRect = newRecommendedRect; + } + + function findChild(item, name) { + for (var i = 0; i < item.children.length; ++i) { + if (item.children[i].objectName === name) { + return item.children[i]; + } + } + return null; + } + + function findParentMatching(item, predicate) { + while (item) { + if (predicate(item)) { + break; + } + item = item.parent; + } + return item; + } + + function findMatchingChildren(item, predicate) { + var results = []; + for (var i in item.children) { + var child = item.children[i]; + if (predicate(child)) { + results.push(child); + } + } + return results; + } + + function isTopLevelWindow(item) { + return item.topLevelWindow; + } + + function isAlwaysOnTopWindow(window) { + return window.alwaysOnTop; + } + + function isModalWindow(window) { + return window.modality !== Qt.NonModal; + } + + function getTopLevelWindows(predicate) { + return findMatchingChildren(desktop, function(child) { + return (isTopLevelWindow(child) && (!predicate || predicate(child))); + }); + } + + function getDesktopWindow(item) { + return findParentMatching(item, isTopLevelWindow) + } + + function fixupZOrder(windows, basis, topWindow) { + windows.sort(function(a, b){ return a.z - b.z; }); + + if ((topWindow.z >= basis) && (windows[windows.length - 1] === topWindow)) { + return; + } + + var lastZ = -1; + var lastTargetZ = basis - 1; + for (var i = 0; i < windows.length; ++i) { + var window = windows[i]; + if (!window.visible) { + continue + } + + if (topWindow && (topWindow === window)) { + continue + } + + if (window.z > lastZ) { + lastZ = window.z; + ++lastTargetZ; + } + if (DebugQML) { + console.log("Assigning z order " + lastTargetZ + " to " + window) + } + + window.z = lastTargetZ; + } + if (topWindow) { + ++lastTargetZ; + if (DebugQML) { + console.log("Assigning z order " + lastTargetZ + " to " + topWindow) + } + topWindow.z = lastTargetZ; + } + + return lastTargetZ; + } + + function raiseWindow(targetWindow) { + var predicate; + var zBasis; + if (isModalWindow(targetWindow)) { + predicate = isModalWindow; + zBasis = zLevels.modal + } else if (isAlwaysOnTopWindow(targetWindow)) { + predicate = function(window) { + return (isAlwaysOnTopWindow(window) && !isModalWindow(window)); + } + zBasis = zLevels.top + } else { + predicate = function(window) { + return (!isAlwaysOnTopWindow(window) && !isModalWindow(window)); + } + zBasis = zLevels.normal + } + + var windows = getTopLevelWindows(predicate); + fixupZOrder(windows, zBasis, targetWindow); + } + + Component.onCompleted: { + //offscreenWindow.activeFocusItemChanged.connect(onWindowFocusChanged); + focusHack.start(); + } + + function onWindowFocusChanged() { + //console.log("Focus item is " + offscreenWindow.activeFocusItem); + + // FIXME this needs more testing before it can go into production + // and I already cant produce any way to have a modal dialog lose focus + // to a non-modal one. + /* + var focusedWindow = getDesktopWindow(offscreenWindow.activeFocusItem); + + if (isModalWindow(focusedWindow)) { + return; + } + + // new focused window is not modal... check if there are any modal windows + var windows = getTopLevelWindows(isModalWindow); + if (0 === windows.length) { + return; + } + + // There are modal windows present, force focus back to the top-most modal window + windows.sort(function(a, b){ return a.z - b.z; }); + windows[windows.length - 1].focus = true; + */ + +// var focusedItem = offscreenWindow.activeFocusItem ; +// if (DebugQML && focusedItem) { +// var rect = desktop.mapFromItem(focusedItem, 0, 0, focusedItem.width, focusedItem.height); +// focusDebugger.x = rect.x; +// focusDebugger.y = rect.y; +// focusDebugger.width = rect.width +// focusDebugger.height = rect.height +// } + } + + function getRepositionChildren(predicate) { + return findMatchingChildren(desktop, function(child) { + return (child.shouldReposition === true && (!predicate || predicate(child))); + }); + } + + function repositionAll() { + if (desktop.repositionLocked) { + return; + } + + var oldRecommendedRect = recommendedRect; + var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height }; + var newRecommendedRect = Controller.getRecommendedHUDRect(); + var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height }; + var windows = d.getTopLevelWindows(); + for (var i = 0; i < windows.length; ++i) { + var targetWindow = windows[i]; + if (targetWindow.visible) { + repositionWindow(targetWindow, true, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions); + } + } + + // also reposition the other children that aren't top level windows but want to be repositioned + var otherChildren = d.getRepositionChildren(); + for (var i = 0; i < otherChildren.length; ++i) { + var child = otherChildren[i]; + repositionWindow(child, true, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions); + } + + } + } + + property bool pinned: false + property var hiddenChildren: [] + + function togglePinned() { + pinned = !pinned + } + + function isPointOnWindow(point) { + for (var i = 0; i < desktop.visibleChildren.length; i++) { + var child = desktop.visibleChildren[i]; + if (child.hasOwnProperty("modality")) { + var mappedPoint = mapToItem(child, point.x, point.y); + if (child.hasOwnProperty("frame")) { + var outLine = child.frame.children[2]; + var framePoint = outLine.mapFromGlobal(point.x, point.y); + if (outLine.contains(framePoint)) { + return true; + } + } + + if (child.contains(mappedPoint)) { + return true; + } + } + } + return false; + } + + function setPinned(newPinned) { + pinned = newPinned + } + + property real unpinnedAlpha: 1.0; + + Behavior on unpinnedAlpha { + NumberAnimation { + easing.type: Easing.Linear; + duration: 300 + } + } + + state: "NORMAL" + states: [ + State { + name: "NORMAL" + PropertyChanges { target: desktop; unpinnedAlpha: 1.0 } + }, + State { + name: "PINNED" + PropertyChanges { target: desktop; unpinnedAlpha: 0.0 } + } + ] + + transitions: [ + Transition { + NumberAnimation { properties: "unpinnedAlpha"; duration: 300 } + } + ] + + onPinnedChanged: { + if (pinned) { + d.raiseWindow(desktop); + desktop.focus = true; + desktop.forceActiveFocus(); + + // recalculate our non-pinned children + hiddenChildren = d.findMatchingChildren(desktop, function(child){ + return !d.isTopLevelWindow(child) && child.visible && !child.pinned; + }); + + hiddenChildren.forEach(function(child){ + child.opacity = Qt.binding(function(){ return desktop.unpinnedAlpha }); + }); + } + state = pinned ? "PINNED" : "NORMAL" + } + + onShowDesktop: pinned = false + + function raise(item) { + var targetWindow = d.getDesktopWindow(item); + if (!targetWindow) { + console.warn("Could not find top level window for " + item); + return; + } + + // Fix up the Z-order (takes into account if this is a modal window) + d.raiseWindow(targetWindow); + var setFocus = true; + if (!d.isModalWindow(targetWindow)) { + var modalWindows = d.getTopLevelWindows(d.isModalWindow); + if (modalWindows.length) { + setFocus = false; + } + } + + if (setFocus) { + targetWindow.focus = true; + } + + showDesktop(); + } + + function ensureTitleBarVisible(targetWindow) { + // Reposition window to ensure that title bar is vertically inside window. + if (targetWindow.frame && targetWindow.frame.decoration) { + var topMargin = -targetWindow.frame.decoration.anchors.topMargin; // Frame's topMargin is a negative value. + targetWindow.y = Math.max(targetWindow.y, topMargin); + } + } + + function centerOnVisible(item) { + var targetWindow = d.getDesktopWindow(item); + if (!targetWindow) { + console.warn("Could not find top level window for " + item); + return; + } + + if (typeof Controller === "undefined") { + console.warn("Controller not yet available... can't center"); + return; + } + + var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedHUDRect(); + var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y, + newRecommendedRectJS.width, + newRecommendedRectJS.height); + var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height }; + var newX = newRecommendedRect.x + ((newRecommendedRect.width - targetWindow.width) / 2); + var newY = newRecommendedRect.y + ((newRecommendedRect.height - targetWindow.height) / 2); + targetWindow.x = newX; + targetWindow.y = newY; + + ensureTitleBarVisible(targetWindow); + + // If we've noticed that our recommended desktop rect has changed, record that change here. + if (recommendedRect != newRecommendedRect) { + recommendedRect = newRecommendedRect; + } + } + + function repositionOnVisible(item) { + var targetWindow = d.getDesktopWindow(item); + if (!targetWindow) { + console.warn("Could not find top level window for " + item); + return; + } + + if (typeof Controller === "undefined") { + console.warn("Controller not yet available... can't reposition targetWindow:" + targetWindow); + return; + } + + var oldRecommendedRect = recommendedRect; + var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height }; + var newRecommendedRect = Controller.getRecommendedHUDRect(); + var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height }; + repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions); + } + + function repositionWindow(targetWindow, forceReposition, + oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions) { + + if (desktop.width === 0 || desktop.height === 0) { + return; + } + + if (!targetWindow) { + console.warn("Could not find top level window for " + item); + return; + } + + var recommended = Controller.getRecommendedHUDRect(); + var maxX = recommended.x + recommended.width; + var maxY = recommended.y + recommended.height; + var newPosition = Qt.vector2d(targetWindow.x, targetWindow.y); + + // if we asked to force reposition, or if the window is completely outside of the recommended rectangle, reposition it + if (forceReposition || (targetWindow.x > maxX || (targetWindow.x + targetWindow.width) < recommended.x) || + (targetWindow.y > maxY || (targetWindow.y + targetWindow.height) < recommended.y)) { + newPosition.x = -1 + newPosition.y = -1 + } + + if (newPosition.x === -1 && newPosition.y === -1) { + var originRelativeX = (targetWindow.x - oldRecommendedRect.x); + var originRelativeY = (targetWindow.y - oldRecommendedRect.y); + if (isNaN(originRelativeX)) { + originRelativeX = 0; + } + if (isNaN(originRelativeY)) { + originRelativeY = 0; + } + var fractionX = Utils.clamp(originRelativeX / oldRecommendedDimmensions.x, 0, 1); + var fractionY = Utils.clamp(originRelativeY / oldRecommendedDimmensions.y, 0, 1); + var newX = (fractionX * newRecommendedDimmensions.x) + newRecommendedRect.x; + var newY = (fractionY * newRecommendedDimmensions.y) + newRecommendedRect.y; + newPosition = Qt.vector2d(newX, newY); + } + targetWindow.x = newPosition.x; + targetWindow.y = newPosition.y; + + ensureTitleBarVisible(targetWindow); + } + + Component { id: messageDialogBuilder; MessageDialog { } } + function messageBox(properties) { + return messageDialogBuilder.createObject(desktop, properties); + } + + Component { id: inputDialogBuilder; QueryDialog { } } + function inputDialog(properties) { + return inputDialogBuilder.createObject(desktop, properties); + } + + Component { id: customInputDialogBuilder; CustomQueryDialog { } } + function customInputDialog(properties) { + return customInputDialogBuilder.createObject(desktop, properties); + } + + Component { id: fileDialogBuilder; FileDialog { } } + function fileDialog(properties) { + return fileDialogBuilder.createObject(desktop, properties); + } + + Component { id: assetDialogBuilder; AssetDialog { } } + function assetDialog(properties) { + return assetDialogBuilder.createObject(desktop, properties); + } + + function unfocusWindows() { + // First find the active focus item, and unfocus it, all the way + // up the parent chain to the window + var currentFocus = offscreenWindow.activeFocusItem; + var targetWindow = d.getDesktopWindow(currentFocus); + while (currentFocus) { + if (currentFocus === targetWindow) { + break; + } + currentFocus.focus = false; + currentFocus = currentFocus.parent; + } + + // Unfocus all windows + var windows = d.getTopLevelWindows(); + for (var i = 0; i < windows.length; ++i) { + windows[i].focus = false; + } + + // For the desktop to have active focus + desktop.focus = true; + desktop.forceActiveFocus(); + } + + function openBrowserWindow(request, profile) { + var component = Qt.createComponent("../Browser.qml"); + var newWindow = component.createObject(desktop); + newWindow.webView.profile = profile; + request.openIn(newWindow.webView); + } + + FocusHack { id: focusHack; } + + Rectangle { + id: focusDebugger; + objectName: "focusDebugger" + z: 9999; visible: false; color: "red" + ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 } + } + + Action { + text: "Toggle Focus Debugger" + shortcut: "Ctrl+Shift+F" + enabled: DebugQML + onTriggered: focusDebugger.visible = !focusDebugger.visible + } + +} diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index e7c68b2a47..5f924834d9 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -8,8 +8,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 +import QtQuick 2.7 import QtQuick.Controls 1.4 +import QtQuick.Controls 2.3 as QQC2 import "../dialogs" import "../js/Utils.js" as Utils @@ -323,6 +324,18 @@ FocusScope { return false; } + function hideDesktopWindows() { + for (var index = 0; index < desktop.visibleChildren.length; index++) { + var child = desktop.visibleChildren[index]; + if (child.topLevelWindow && child.hasOwnProperty("modality")) { + var TOOLBAR_NAME = "com.highfidelity.interface.toolbar.system" + if (child.objectName !== TOOLBAR_NAME) { + child.setShown(false); + } + } + } + } + function setPinned(newPinned) { pinned = newPinned } @@ -565,7 +578,7 @@ FocusScope { ColorAnimation on color { from: "#7fffff00"; to: "#7f0000ff"; duration: 1000; loops: 9999 } } - Action { + QQC2.Action { text: "Toggle Focus Debugger" shortcut: "Ctrl+Shift+F" enabled: DebugQML diff --git a/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml b/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml new file mode 100644 index 0000000000..b1b6de4644 --- /dev/null +++ b/interface/resources/qml/dialogs/+android/CustomQueryDialog.qml @@ -0,0 +1,338 @@ +// +// CustomQueryDialog.qml +// +// Created by Zander Otavka on 7/14/16 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7; +import QtQuick.Dialogs 1.2 as OriginalDialogs; +import QtQuick.Controls 1.4; + +import "../controls-uit"; +import "../styles-uit"; +import "../windows"; + +ModalWindow { + id: root; + HifiConstants { id: hifi; } + implicitWidth: 640; + implicitHeight: 320; + visible: true; + keyboardOverride: true // Disable ModalWindow's keyboard. + + signal selected(var result); + signal canceled(); + + property int icon: hifi.icons.none; + property string iconText: ""; + property int iconSize: 35; + onIconChanged: updateIcon(); + + property var textInput; + property var comboBox; + property var checkBox; + onTextInputChanged: { + if (textInput && textInput.text !== undefined) { + textField.text = textInput.text; + } + } + onComboBoxChanged: { + if (comboBox && comboBox.index !== undefined) { + comboBoxField.currentIndex = comboBox.index; + } + } + onCheckBoxChanged: { + if (checkBox && checkBox.checked !== undefined) { + checkBoxField.checked = checkBox.checked; + } + } + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + onKeyboardRaisedChanged: d.resize(); + + property var warning: ""; + property var result; + + property var implicitCheckState: null; + + property int titleWidth: 0; + onTitleWidthChanged: d.resize(); + + function updateIcon() { + if (!root) { + return; + } + iconText = hifi.glyphForIcon(root.icon); + } + + function updateCheckbox() { + if (checkBox.disableForItems) { + var currentItemInDisableList = false; + for (var i in checkBox.disableForItems) { + if (comboBoxField.currentIndex === checkBox.disableForItems[i]) { + currentItemInDisableList = true; + break; + } + } + + if (currentItemInDisableList) { + checkBoxField.enabled = false; + if (checkBox.checkStateOnDisable !== null && checkBox.checkStateOnDisable !== undefined) { + root.implicitCheckState = checkBoxField.checked; + checkBoxField.checked = checkBox.checkStateOnDisable; + } + root.warning = checkBox.warningOnDisable; + } else { + checkBoxField.enabled = true; + if (root.implicitCheckState !== null) { + checkBoxField.checked = root.implicitCheckState; + root.implicitCheckState = null; + } + root.warning = ""; + } + } + } + + Item { + clip: true; + width: pane.width; + height: pane.height; + anchors.margins: 0; + + QtObject { + id: d; + readonly property int minWidth: 480 + readonly property int maxWdith: 1280 + readonly property int minHeight: 120 + readonly property int maxHeight: 720 + + function resize() { + var targetWidth = Math.max(titleWidth, pane.width); + var targetHeight = (textField.visible ? textField.controlHeight + hifi.dimensions.contentSpacing.y : 0) + + (extraInputs.visible ? extraInputs.height + hifi.dimensions.contentSpacing.y : 0) + + (buttons.height + 3 * hifi.dimensions.contentSpacing.y) + + ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + hifi.dimensions.contentSpacing.y) : 0); + + root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth); + root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? + d.maxHeight : targetHeight); + } + } + + Item { + anchors { + top: parent.top; + bottom: extraInputs.visible ? extraInputs.top : buttons.top; + left: parent.left; + right: parent.right; + margins: 0; + } + + // FIXME make a text field type that can be bound to a history for autocompletion + TextField { + id: textField; + label: root.textInput.label; + focus: root.textInput ? true : false; + visible: root.textInput ? true : false; + anchors { + left: parent.left; + right: parent.right; + bottom: keyboard.top; + bottomMargin: hifi.dimensions.contentSpacing.y; + } + } + + Keyboard { + id: keyboard + raised: keyboardEnabled && keyboardRaised + numeric: punctuationMode + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + bottomMargin: raised ? hifi.dimensions.contentSpacing.y : 0 + } + } + } + + Item { + id: extraInputs; + visible: Boolean(root.checkBox || root.comboBox); + anchors { + left: parent.left; + right: parent.right; + bottom: buttons.top; + bottomMargin: hifi.dimensions.contentSpacing.y; + } + height: comboBoxField.controlHeight; + onHeightChanged: d.resize(); + onWidthChanged: d.resize(); + + CheckBox { + id: checkBoxField; + text: root.checkBox.label; + focus: Boolean(root.checkBox); + visible: Boolean(root.checkBox); + anchors { + left: parent.left; + bottom: parent.bottom; + leftMargin: 6; // Magic number to align with warning icon + bottomMargin: 6; + } + } + + ComboBox { + id: comboBoxField; + label: root.comboBox.label; + focus: Boolean(root.comboBox); + visible: Boolean(root.comboBox); + Binding on x { + when: comboBoxField.visible + value: !checkBoxField.visible ? buttons.x : acceptButton.x + } + + Binding on width { + when: comboBoxField.visible + value: !checkBoxField.visible ? buttons.width : buttons.width - acceptButton.x + } + anchors { + right: parent.right; + bottom: parent.bottom; + } + model: root.comboBox ? root.comboBox.items : []; + onAccepted: { + updateCheckbox(); + focus = true; + } + } + } + + Row { + id: buttons; + focus: true; + spacing: hifi.dimensions.contentSpacing.x; + layoutDirection: Qt.RightToLeft; + onHeightChanged: d.resize(); + onWidthChanged: { + d.resize(); + resizeWarningText(); + } + + anchors { + bottom: parent.bottom; + left: parent.left; + right: parent.right; + bottomMargin: hifi.dimensions.contentSpacing.y; + } + + function resizeWarningText() { + var rowWidth = buttons.width; + var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2; + var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x; + warningText.width = rowWidth - buttonsWidth - warningIconWidth; + } + + Button { + id: cancelButton; + action: cancelAction; + } + + Button { + id: acceptButton; + action: acceptAction; + } + + Text { + id: warningText; + visible: Boolean(root.warning); + text: root.warning; + wrapMode: Text.WordWrap; + font.italic: true; + maximumLineCount: 2; + } + + HiFiGlyphs { + id: warningIcon; + visible: Boolean(root.warning); + text: hifi.glyphs.alert; + size: hifi.dimensions.controlLineHeight; + width: 20 // Line up with checkbox. + } + } + + Action { + id: cancelAction; + text: qsTr("Cancel"); + shortcut: "Esc"; + onTriggered: { + root.result = null; + root.canceled(); + // FIXME we are leaking memory to avoid a crash + // root.destroy(); + + root.disableFade = true + visible = false; + } + } + + Action { + id: acceptAction; + text: qsTr("Add"); + shortcut: "Return" + onTriggered: { + var result = {}; + if (textInput) { + result.textInput = textField.text; + } + if (comboBox) { + result.comboBox = comboBoxField.currentIndex; + result.comboBoxText = comboBoxField.currentText; + } + if (checkBox) { + result.checkBox = checkBoxField.enabled ? checkBoxField.checked : null; + } + root.result = JSON.stringify(result); + root.selected(root.result); + // FIXME we are leaking memory to avoid a crash + // root.destroy(); + + root.disableFade = true + visible = false; + } + } + } + + Keys.onPressed: { + if (!visible) { + return; + } + + switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + cancelAction.trigger(); + event.accepted = true; + break; + + case Qt.Key_Return: + case Qt.Key_Enter: + acceptAction.trigger(); + event.accepted = true; + break; + } + } + + Component.onCompleted: { + keyboardEnabled = HMD.active; + updateIcon(); + updateCheckbox(); + d.resize(); + textField.forceActiveFocus(); + } +} diff --git a/interface/resources/qml/dialogs/+android/FileDialog.qml b/interface/resources/qml/dialogs/+android/FileDialog.qml new file mode 100644 index 0000000000..548ab453a7 --- /dev/null +++ b/interface/resources/qml/dialogs/+android/FileDialog.qml @@ -0,0 +1,840 @@ +// +// FileDialog.qml +// +// Created by Bradley Austin Davis on 14 Jan 2016 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import Qt.labs.folderlistmodel 2.1 +import Qt.labs.settings 1.0 +import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Controls 1.4 + +import ".." +import "../controls-uit" +import "../styles-uit" +import "../windows" + +import "fileDialog" + +//FIXME implement shortcuts for favorite location +ModalWindow { + id: root + resizable: true + implicitWidth: 480 + implicitHeight: 360 + (fileDialogItem.keyboardEnabled && fileDialogItem.keyboardRaised ? keyboard.raisedHeight + hifi.dimensions.contentSpacing.y : 0) + + minSize: Qt.vector2d(360, 240) + draggable: true + + HifiConstants { id: hifi } + + property var filesModel: ListModel { } + + Settings { + category: "FileDialog" + property alias width: root.width + property alias height: root.height + property alias x: root.x + property alias y: root.y + } + + + // Set from OffscreenUi::getOpenFile() + property alias caption: root.title; + // Set from OffscreenUi::getOpenFile() + property alias dir: fileTableModel.folder; + // Set from OffscreenUi::getOpenFile() + property alias filter: selectionType.filtersString; + // Set from OffscreenUi::getOpenFile() + property int options; // <-- FIXME unused + + property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : "" + property int iconSize: 40 + + property bool selectDirectory: false; + property bool showHidden: false; + // FIXME implement + property bool multiSelect: false; + property bool saveDialog: false; + property var helper: fileDialogHelper + property alias model: fileTableView.model + property var drives: helper.drives() + + property int titleWidth: 0 + + 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); + + fileDialogItem.keyboardEnabled = HMD.active; + + // HACK: The following lines force the model to initialize properly such that the go-up button + // works properly from the initial screen. + var initialFolder = folderListModel.folder; + fileTableModel.folder = helper.pathToUrl(drives[0]); + fileTableModel.folder = initialFolder; + + iconText = root.title !== "" ? hifi.glyphs.scriptUpload : ""; + + // Clear selection when click on external frame. + frameClicked.connect(function() { d.clearSelection(); }); + + if (selectDirectory) { + currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder)); + d.currentSelectionIsFolder = true; + d.currentSelectionUrl = initialFolder; + } + + helper.contentsChanged.connect(function() { + if (folderListModel) { + // Make folderListModel refresh. + var save = folderListModel.folder; + folderListModel.folder = ""; + folderListModel.folder = save; + } + }); + + focusTimer.start(); + } + + Timer { + id: focusTimer + interval: 10 + running: false + repeat: false + onTriggered: { + fileTableView.contentItem.forceActiveFocus(); + } + } + + Item { + id: fileDialogItem + clip: true + width: pane.width + height: pane.height + anchors.margins: 0 + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + MouseArea { + // Clear selection when click on internal unused area. + anchors.fill: parent + drag.target: root + onClicked: { + d.clearSelection(); + // Defocus text field so that the keyboard gets hidden. + // Clicking also breaks keyboard navigation apart from backtabbing to cancel + frame.forceActiveFocus(); + } + } + + Row { + id: navControls + anchors { + top: parent.top + topMargin: hifi.dimensions.contentMargin.y + left: parent.left + } + spacing: hifi.dimensions.contentSpacing.x + + GlyphButton { + id: upButton + glyph: hifi.glyphs.levelUp + width: height + size: 30 + enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== "" + onClicked: d.navigateUp(); + Keys.onReturnPressed: { d.navigateUp(); } + KeyNavigation.tab: homeButton + KeyNavigation.backtab: upButton + KeyNavigation.left: upButton + KeyNavigation.right: homeButton + } + + GlyphButton { + id: homeButton + property var destination: helper.home(); + glyph: hifi.glyphs.home + size: 28 + width: height + enabled: d.homeDestination ? true : false + onClicked: d.navigateHome(); + Keys.onReturnPressed: { d.navigateHome(); } + KeyNavigation.tab: fileTableView.contentItem + KeyNavigation.backtab: upButton + KeyNavigation.left: upButton + } + } + + ComboBox { + id: pathSelector + anchors { + top: parent.top + topMargin: hifi.dimensions.contentMargin.y + left: navControls.right + leftMargin: hifi.dimensions.contentSpacing.x + right: parent.right + } + + property var lastValidFolder: helper.urlToPath(fileTableModel.folder) + + function calculatePathChoices(folder) { + var folders = folder.split("/"), + choices = [], + i, length; + + if (folders[folders.length - 1] === "") { + folders.pop(); + } + + choices.push(folders[0]); + + for (i = 1, length = folders.length; i < length; i++) { + choices.push(choices[i - 1] + "/" + folders[i]); + } + + if (folders[0] === "") { + // Special handling for OSX root dir. + choices[0] = "/"; + } + + choices.reverse(); + + if (drives && drives.length > 1) { + choices.push("This PC"); + } + + if (choices.length > 0) { + pathSelector.model = choices; + } + } + + onLastValidFolderChanged: { + var folder = d.capitalizeDrive(lastValidFolder); + calculatePathChoices(folder); + } + + onCurrentTextChanged: { + var folder = currentText; + + if (/^[a-zA-z]:$/.test(folder)) { + folder = "file:///" + folder + "/"; + } else if (folder === "This PC") { + folder = "file:///"; + } else { + folder = helper.pathToUrl(folder); + } + + if (helper.urlToPath(folder).toLowerCase() !== helper.urlToPath(fileTableModel.folder).toLowerCase()) { + if (root.selectDirectory) { + currentSelection.text = currentText !== "This PC" ? currentText : ""; + d.currentSelectionUrl = helper.pathToUrl(currentText); + } + fileTableModel.folder = folder; + } + } + + KeyNavigation.up: fileTableView.contentItem + KeyNavigation.down: fileTableView.contentItem + KeyNavigation.tab: fileTableView.contentItem + KeyNavigation.backtab: fileTableView.contentItem + KeyNavigation.left: fileTableView.contentItem + KeyNavigation.right: fileTableView.contentItem + } + + QtObject { + id: d + property var currentSelectionUrl; + readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl); + property bool currentSelectionIsFolder; + property var backStack: [] + property var tableViewConnection: Connections { target: fileTableView; onCurrentRowChanged: d.update(); } + property var modelConnection: Connections { target: fileTableModel; onFolderChanged: d.update(); } + property var homeDestination: helper.home(); + + function capitalizeDrive(path) { + // Consistently capitalize drive letter for Windows. + if (/[a-zA-Z]:/.test(path)) { + return path.charAt(0).toUpperCase() + path.slice(1); + } + return path; + } + + function update() { + var row = fileTableView.currentRow; + + if (row === -1) { + if (!root.selectDirectory) { + currentSelection.text = ""; + currentSelectionIsFolder = false; + } + return; + } + + currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath); + currentSelectionIsFolder = fileTableView.model !== filesModel ? + fileTableView.model.isFolder(row) : + fileTableModel.isFolder(row); + if (root.selectDirectory || !currentSelectionIsFolder) { + currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl)); + } else { + currentSelection.text = ""; + } + } + + function navigateUp() { + if (fileTableModel.parentFolder && fileTableModel.parentFolder !== "") { + fileTableModel.folder = fileTableModel.parentFolder; + return true; + } + } + + function navigateHome() { + fileTableModel.folder = homeDestination; + return true; + } + + function clearSelection() { + fileTableView.selection.clear(); + fileTableView.currentRow = -1; + update(); + } + } + + FolderListModel { + id: folderListModel + nameFilters: selectionType.currentFilter + showDirsFirst: true + showDotAndDotDot: false + showFiles: !root.selectDirectory + Component.onCompleted: { + showFiles = !root.selectDirectory + } + + onFolderChanged: { + fileTableModel.update(); // Update once the data from the folder change is available. + } + + function getItem(index, field) { + return get(index, field); + } + } + + ListModel { + // Emulates FolderListModel but contains drive data. + id: driveListModel + + property int count: 1 + + Component.onCompleted: initialize(); + + function initialize() { + var drive, + i; + + count = drives.length; + + for (i = 0; i < count; i++) { + drive = drives[i].slice(0, -1); // Remove trailing "/". + append({ + fileName: drive, + fileModified: new Date(0), + fileSize: 0, + filePath: drive + "/", + fileIsDir: true, + fileNameSort: drive.toLowerCase() + }); + } + } + + function getItem(index, field) { + return get(index)[field]; + } + } + + Component { + id: filesModelBuilder + ListModel { } + } + + QtObject { + id: fileTableModel + + // FolderListModel has a couple of problems: + // 1) Files and directories sort case-sensitively: https://bugreports.qt.io/browse/QTBUG-48757 + // 2) Cannot browse up to the "computer" level to view Windows drives: https://bugreports.qt.io/browse/QTBUG-42901 + // + // To solve these problems an intermediary ListModel is used that implements proper sorting and can be populated with + // drive information when viewing at the computer level. + + property var folder + property int sortOrder: Qt.AscendingOrder + property int sortColumn: 0 + property var model: folderListModel + property string parentFolder: calculateParentFolder(); + + readonly property string rootFolder: "file:///" + + function calculateParentFolder() { + if (model === folderListModel) { + if (folderListModel.parentFolder.toString() === "" && driveListModel.count > 1) { + return rootFolder; + } else { + return folderListModel.parentFolder; + } + } else { + return ""; + } + } + + onFolderChanged: { + if (folder === rootFolder) { + model = driveListModel; + helper.monitorDirectory(""); + update(); + } else { + var needsUpdate = model === driveListModel && folder === folderListModel.folder; + + model = folderListModel; + folderListModel.folder = folder; + helper.monitorDirectory(helper.urlToPath(folder)); + + if (needsUpdate) { + update(); + } + } + } + + function isFolder(row) { + if (row === -1) { + return false; + } + return filesModel.get(row).fileIsDir; + } + + function get(row) { + return filesModel.get(row) + } + + function update() { + var dataFields = ["fileName", "fileModified", "fileSize"], + sortFields = ["fileNameSort", "fileModified", "fileSize"], + dataField = dataFields[sortColumn], + sortField = sortFields[sortColumn], + sortValue, + fileName, + fileIsDir, + comparisonFunction, + lower, + middle, + upper, + rows = 0, + i; + + var newFilesModel = filesModelBuilder.createObject(root); + + comparisonFunction = sortOrder === Qt.AscendingOrder + ? function(a, b) { return a < b; } + : function(a, b) { return a > b; } + + for (i = 0; i < model.count; i++) { + fileName = model.getItem(i, "fileName"); + fileIsDir = model.getItem(i, "fileIsDir"); + + sortValue = model.getItem(i, dataField); + if (dataField === "fileName") { + // Directories first by prefixing a "*". + // Case-insensitive. + sortValue = (fileIsDir ? "*" : "") + sortValue.toLowerCase(); + } + + lower = 0; + upper = rows; + while (lower < upper) { + middle = Math.floor((lower + upper) / 2); + var lessThan; + if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) { + lessThan = true; + upper = middle; + } else { + lessThan = false; + lower = middle + 1; + } + } + + newFilesModel.insert(lower, { + fileName: fileName, + fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")), + fileSize: model.getItem(i, "fileSize"), + filePath: model.getItem(i, "filePath"), + fileIsDir: fileIsDir, + fileNameSort: (fileIsDir ? "*" : "") + fileName.toLowerCase() + }); + + rows++; + } + filesModel = newFilesModel; + + d.clearSelection(); + } + } + + Table { + id: fileTableView + colorScheme: hifi.colorSchemes.light + anchors { + top: navControls.bottom + topMargin: hifi.dimensions.contentSpacing.y + left: parent.left + right: parent.right + bottom: currentSelection.top + bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height + } + headerVisible: !selectDirectory + onDoubleClicked: navigateToRow(row); + Keys.onReturnPressed: navigateToCurrentRow(); + Keys.onEnterPressed: navigateToCurrentRow(); + + sortIndicatorColumn: 0 + sortIndicatorOrder: Qt.AscendingOrder + sortIndicatorVisible: true + + model: filesModel + + function updateSort() { + fileTableModel.sortOrder = sortIndicatorOrder; + fileTableModel.sortColumn = sortIndicatorColumn; + fileTableModel.update(); + } + + onSortIndicatorColumnChanged: { updateSort(); } + + onSortIndicatorOrderChanged: { updateSort(); } + + itemDelegate: Item { + clip: true + + FiraSansSemiBold { + text: getText(); + elide: styleData.elideMode + anchors { + left: parent.left + leftMargin: hifi.dimensions.tablePadding + right: parent.right + rightMargin: hifi.dimensions.tablePadding + verticalCenter: parent.verticalCenter + } + size: hifi.fontSizes.tableText + color: hifi.colors.baseGrayHighlight + font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir) + ? "Fira Sans SemiBold" : "Fira Sans" + + function getText() { + if (styleData.row === -1) { + return styleData.value; + } + + switch (styleData.column) { + case 1: return fileTableView.model.get(styleData.row).fileIsDir ? "" : styleData.value; + case 2: return fileTableView.model.get(styleData.row).fileIsDir ? "" : formatSize(styleData.value); + default: return styleData.value; + } + } + function formatSize(size) { + var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ]; + var suffixIndex = 0 + while ((size / 1024.0) > 1.1) { + size /= 1024.0; + ++suffixIndex; + } + + size = Math.round(size*1000)/1000; + size = size.toLocaleString() + + return size + " " + suffixes[suffixIndex]; + } + } + } + + TableViewColumn { + id: fileNameColumn + role: "fileName" + title: "Name" + width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width + movable: false + resizable: true + } + TableViewColumn { + id: fileModifiedColumn + role: "fileModified" + title: "Date" + width: 0.3 * fileTableView.width + movable: false + resizable: true + visible: !selectDirectory + } + TableViewColumn { + role: "fileSize" + title: "Size" + width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width + movable: false + resizable: true + visible: !selectDirectory + } + + function navigateToRow(row) { + currentRow = row; + navigateToCurrentRow(); + } + + function navigateToCurrentRow() { + var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel + var row = fileTableView.currentRow + var isFolder = currentModel.isFolder(row); + var file = currentModel.get(row).filePath; + if (isFolder) { + currentModel.folder = helper.pathToUrl(file); + } else { + okAction.trigger(); + } + } + + property string prefix: "" + + function addToPrefix(event) { + if (!event.text || event.text === "") { + return false; + } + var newPrefix = prefix + event.text.toLowerCase(); + var matchedIndex = -1; + for (var i = 0; i < model.count; ++i) { + var name = model !== filesModel ? model.get(i).fileName.toLowerCase() : + filesModel.get(i).fileName.toLowerCase(); + if (0 === name.indexOf(newPrefix)) { + matchedIndex = i; + break; + } + } + + if (matchedIndex !== -1) { + fileTableView.selection.clear(); + fileTableView.selection.select(matchedIndex); + fileTableView.currentRow = matchedIndex; + fileTableView.prefix = newPrefix; + } + prefixClearTimer.restart(); + return true; + } + + Timer { + id: prefixClearTimer + interval: 1000 + repeat: false + running: false + onTriggered: fileTableView.prefix = ""; + } + + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Backspace: + case Qt.Key_Tab: + 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 + } else { + event.accepted = false; + } + break; + } + } + + KeyNavigation.tab: root.saveDialog ? currentSelection : openButton + } + + TextField { + id: currentSelection + label: selectDirectory ? "Directory:" : "File name:" + anchors { + left: parent.left + right: selectionType.visible ? selectionType.left: parent.right + rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0 + bottom: keyboard.top + bottomMargin: hifi.dimensions.contentSpacing.y + } + readOnly: !root.saveDialog + activeFocusOnTab: !readOnly + onActiveFocusChanged: if (activeFocus) { selectAll(); } + onAccepted: okAction.trigger(); + KeyNavigation.up: fileTableView.contentItem + KeyNavigation.down: openButton + KeyNavigation.tab: openButton + KeyNavigation.backtab: fileTableView.contentItem + } + + FileTypeSelection { + id: selectionType + anchors { + top: currentSelection.top + left: buttonRow.left + right: parent.right + } + visible: !selectDirectory && filtersCount > 1 + } + + Keyboard { + id: keyboard + raised: parent.keyboardEnabled && parent.keyboardRaised + numeric: parent.punctuationMode + anchors { + left: parent.left + right: parent.right + bottom: buttonRow.top + bottomMargin: visible ? hifi.dimensions.contentSpacing.y : 0 + } + } + + Row { + id: buttonRow + anchors { + right: parent.right + bottom: parent.bottom + } + spacing: hifi.dimensions.contentSpacing.y + + Button { + id: openButton + color: hifi.buttons.blue + action: okAction + Keys.onReturnPressed: okAction.trigger() + KeyNavigation.right: cancelButton + KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem + KeyNavigation.tab: cancelButton + } + + Button { + id: cancelButton + action: cancelAction + Keys.onReturnPressed: { cancelAction.trigger() } + KeyNavigation.left: openButton + KeyNavigation.up: root.saveDialog ? currentSelection : fileTableView.contentItem + KeyNavigation.backtab: openButton + } + } + + Action { + id: okAction + text: currentSelection.text ? (root.selectDirectory && fileTableView.currentRow === -1 ? "Choose" : (root.saveDialog ? "Save" : "Open")) : "Open" + enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false + onTriggered: { + if (!root.selectDirectory && !d.currentSelectionIsFolder + || root.selectDirectory && fileTableView.currentRow === -1) { + okActionTimer.start(); + } else { + fileTableView.navigateToCurrentRow(); + } + } + } + + Timer { + id: okActionTimer + interval: 50 + running: false + repeat: false + onTriggered: { + if (!root.saveDialog) { + selectedFile(d.currentSelectionUrl); + root.destroy() + return; + } + + // Handle the ambiguity between different cases + // * typed name (with or without extension) + // * full path vs relative vs filename only + var selection = helper.saveHelper(currentSelection.text, root.dir, selectionType.currentFilter); + + if (!selection) { + desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Warning, text: "Unable to parse selection" }) + return; + } + + if (helper.urlIsDir(selection)) { + root.dir = selection; + currentSelection.text = ""; + return; + } + + // Check if the file is a valid target + if (!helper.urlIsWritable(selection)) { + desktop.messageBox({ + icon: OriginalDialogs.StandardIcon.Warning, + text: "Unable to write to location " + selection + }) + return; + } + + if (helper.urlExists(selection)) { + var messageBox = desktop.messageBox({ + icon: OriginalDialogs.StandardIcon.Question, + buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, + text: "Do you wish to overwrite " + selection + "?", + }); + var result = messageBox.exec(); + if (OriginalDialogs.StandardButton.Yes !== result) { + return; + } + } + + console.log("Selecting " + selection) + selectedFile(selection); + root.destroy(); + } + } + + Action { + id: cancelAction + text: "Cancel" + onTriggered: { canceled(); root.shown = false; } + } + } + + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Backspace: + event.accepted = d.navigateUp(); + break; + + case Qt.Key_Home: + event.accepted = d.navigateHome(); + break; + + case Qt.Key_Escape: + event.accepted = true; + root.click(OriginalDialogs.StandardButton.Cancel); + break; + } + } +} diff --git a/interface/resources/qml/dialogs/+android/QueryDialog.qml b/interface/resources/qml/dialogs/+android/QueryDialog.qml new file mode 100644 index 0000000000..aec6d8a286 --- /dev/null +++ b/interface/resources/qml/dialogs/+android/QueryDialog.qml @@ -0,0 +1,231 @@ +// +// QueryDialog.qml +// +// Created by Bradley Austin Davis on 22 Jan 2016 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import QtQuick.Controls 1.4 + +import "../controls-uit" +import "../styles-uit" +import "../windows" + +ModalWindow { + id: root + HifiConstants { id: hifi } + implicitWidth: 640 + implicitHeight: 320 + visible: true + keyboardOverride: true // Disable ModalWindow's keyboard. + + signal selected(var result); + signal canceled(); + + property int icon: hifi.icons.none + property string iconText: "" + property int iconSize: 35 + onIconChanged: updateIcon(); + + property var items; + property string label + property var result; + property alias current: textResult.text + + // For text boxes + property alias placeholderText: textResult.placeholderText + + // For combo boxes + property bool editable: true; + + property int titleWidth: 0 + onTitleWidthChanged: d.resize(); + + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + onKeyboardRaisedChanged: d.resize(); + + function updateIcon() { + if (!root) { + return; + } + iconText = hifi.glyphForIcon(root.icon); + } + + Item { + id: modalWindowItem + clip: true + width: pane.width + height: pane.height + anchors.margins: 0 + + QtObject { + id: d + readonly property int minWidth: 480 + readonly property int maxWdith: 1280 + readonly property int minHeight: 120 + readonly property int maxHeight: 720 + + function resize() { + var targetWidth = Math.max(titleWidth, pane.width) + var targetHeight = (items ? comboBox.controlHeight : textResult.controlHeight) + 5 * hifi.dimensions.contentSpacing.y + buttons.height + root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth); + root.height = ((targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight)) + ((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + 2 * hifi.dimensions.contentSpacing.y) : 0) + } + } + + Item { + anchors { + top: parent.top + bottom: keyboard.top; + left: parent.left; + right: parent.right; + margins: 0 + bottomMargin: 2 * hifi.dimensions.contentSpacing.y + } + + // FIXME make a text field type that can be bound to a history for autocompletion + TextField { + id: textResult + label: root.label + visible: items ? false : true + anchors { + left: parent.left; + right: parent.right; + bottom: parent.bottom + } + KeyNavigation.down: acceptButton + KeyNavigation.tab: acceptButton + } + + ComboBox { + id: comboBox + label: root.label + visible: items ? true : false + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + model: items ? items : [] + KeyNavigation.down: acceptButton + KeyNavigation.tab: acceptButton + } + } + + property alias keyboardOverride: root.keyboardOverride + property alias keyboardRaised: root.keyboardRaised + property alias punctuationMode: root.punctuationMode + Keyboard { + id: keyboard + raised: keyboardEnabled && keyboardRaised + numeric: punctuationMode + anchors { + left: parent.left + right: parent.right + bottom: buttons.top + bottomMargin: raised ? 2 * hifi.dimensions.contentSpacing.y : 0 + } + } + + Flow { + id: buttons + spacing: hifi.dimensions.contentSpacing.x + onHeightChanged: d.resize(); onWidthChanged: d.resize(); + layoutDirection: Qt.RightToLeft + anchors { + bottom: parent.bottom + right: parent.right + margins: 0 + bottomMargin: hifi.dimensions.contentSpacing.y + } + Button { + id: cancelButton + action: cancelAction + KeyNavigation.left: acceptButton + KeyNavigation.up: items ? comboBox : textResult + KeyNavigation.backtab: acceptButton + } + Button { + id: acceptButton + action: acceptAction + KeyNavigation.right: cancelButton + KeyNavigation.up: items ? comboBox : textResult + KeyNavigation.tab: cancelButton + KeyNavigation.backtab: items ? comboBox : textResult + } + } + + Action { + id: cancelAction + text: qsTr("Cancel"); + shortcut: "Esc" + onTriggered: { + root.canceled(); + // FIXME we are leaking memory to avoid a crash + // root.destroy(); + + root.disableFade = true + visible = false; + } + } + + Action { + id: acceptAction + text: qsTr("OK"); + shortcut: "Return" + onTriggered: { + root.result = items ? comboBox.currentText : textResult.text + root.selected(root.result); + // FIXME we are leaking memory to avoid a crash + // root.destroy(); + + root.disableFade = true + visible = false; + } + } + } + + Keys.onPressed: { + if (!visible) { + return + } + + switch (event.key) { + case Qt.Key_Escape: + case Qt.Key_Back: + cancelAction.trigger() + event.accepted = true; + break; + + case Qt.Key_Return: + case Qt.Key_Enter: + if (acceptButton.focus) { + acceptAction.trigger() + } else if (cancelButton.focus) { + cancelAction.trigger() + } else if (comboBox.focus || comboBox.popup.focus) { + comboBox.showList() + } + event.accepted = true; + break; + } + } + + Component.onCompleted: { + keyboardEnabled = HMD.active; + updateIcon(); + d.resize(); + if (items) { + comboBox.forceActiveFocus() + } else { + textResult.forceActiveFocus() + } + } +} diff --git a/interface/resources/qml/dialogs/AssetDialog.qml b/interface/resources/qml/dialogs/AssetDialog.qml index 8d19d38efb..e8d28e9b37 100644 --- a/interface/resources/qml/dialogs/AssetDialog.qml +++ b/interface/resources/qml/dialogs/AssetDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import Qt.labs.settings 1.0 import "../styles-uit" diff --git a/interface/resources/qml/dialogs/CustomQueryDialog.qml b/interface/resources/qml/dialogs/CustomQueryDialog.qml index 6ce4722d04..008ed5b860 100644 --- a/interface/resources/qml/dialogs/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/CustomQueryDialog.qml @@ -8,9 +8,9 @@ // 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 QtQuick 2.7; import QtQuick.Dialogs 1.2 as OriginalDialogs; +import QtQuick.Controls 2.3 import "../controls-uit"; import "../styles-uit"; @@ -122,12 +122,6 @@ ModalWindow { root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth); root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight); - if (checkBoxField.visible && comboBoxField.visible) { - checkBoxField.width = extraInputs.width / 2; - comboBoxField.width = extraInputs.width / 2; - } else if (!checkBoxField.visible && comboBoxField.visible) { - comboBoxField.width = extraInputs.width; - } } } @@ -198,6 +192,15 @@ ModalWindow { label: root.comboBox.label; focus: Boolean(root.comboBox); visible: Boolean(root.comboBox); + Binding on x { + when: comboBoxField.visible + value: !checkBoxField.visible ? buttons.x : acceptButton.x + } + + Binding on width { + when: comboBoxField.visible + value: !checkBoxField.visible ? buttons.width : buttons.width - acceptButton.x + } anchors { right: parent.right; bottom: parent.bottom; @@ -266,7 +269,7 @@ ModalWindow { Action { id: cancelAction; text: qsTr("Cancel"); - shortcut: Qt.Key_Escape; + shortcut: "Esc"; onTriggered: { root.result = null; root.canceled(); @@ -281,7 +284,7 @@ ModalWindow { Action { id: acceptAction; text: qsTr("Add"); - shortcut: Qt.Key_Return; + shortcut: "Return" onTriggered: { var result = {}; if (textInput) { diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 572e7a7918..154d66378b 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -8,12 +8,12 @@ // 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 QtQuick 2.7 import Qt.labs.folderlistmodel 2.1 import Qt.labs.settings 1.0 -import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Controls 1.4 as QQC1 +import QtQuick.Controls 2.3 import ".." import "../controls-uit" @@ -574,7 +574,7 @@ ModalWindow { } } - TableViewColumn { + QQC1.TableViewColumn { id: fileNameColumn role: "fileName" title: "Name" @@ -582,7 +582,7 @@ ModalWindow { movable: false resizable: true } - TableViewColumn { + QQC1.TableViewColumn { id: fileModifiedColumn role: "fileModified" title: "Date" @@ -591,7 +591,7 @@ ModalWindow { resizable: true visible: !selectDirectory } - TableViewColumn { + QQC1.TableViewColumn { role: "fileSize" title: "Size" width: fileTableView.width - fileNameColumn.width - fileModifiedColumn.width diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index 351df6dc8a..b5ac6cab72 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import "../controls-uit" diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index e16f3aa12d..0a97ab9241 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../controls-uit" as HifiControls import "../styles-uit" @@ -27,7 +26,7 @@ ScrollingWindow { property var showCategories: [] minSize: Qt.vector2d(400, 500) - HifiConstants { id: hifi } + //HifiConstants { id: hifi } function saveAll() { for (var i = 0; i < sections.length; ++i) { @@ -97,19 +96,19 @@ ScrollingWindow { anchors { top: parent.top right: parent.right - rightMargin: hifi.dimensions.contentMargin.x + rightMargin: 10//hifi.dimensions.contentMargin.x } - spacing: hifi.dimensions.contentSpacing.x + spacing: 1//hifi.dimensions.contentSpacing.x HifiControls.Button { text: "Save changes" - color: hifi.buttons.blue + color: 1//hifi.buttons.blue onClicked: root.saveAll() } HifiControls.Button { text: "Cancel" - color: hifi.buttons.white + color: 2//hifi.buttons.white onClicked: root.restoreAll() } } diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index ec62f16087..41ee30e6d5 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -8,9 +8,8 @@ // 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 QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick 2.7 +import QtQuick.Controls 2.3 import "../controls-uit" import "../styles-uit" @@ -165,8 +164,8 @@ ModalWindow { Action { id: cancelAction - text: qsTr("Cancel") - shortcut: Qt.Key_Escape + text: qsTr("Cancel"); + shortcut: "Esc" onTriggered: { root.canceled(); // FIXME we are leaking memory to avoid a crash @@ -176,10 +175,11 @@ ModalWindow { visible = false; } } + Action { id: acceptAction - text: qsTr("OK") - shortcut: Qt.Key_Return + text: qsTr("OK"); + shortcut: "Return" onTriggered: { root.result = items ? comboBox.currentText : textResult.text root.selected(root.result); diff --git a/interface/resources/qml/dialogs/TabletAssetDialog.qml b/interface/resources/qml/dialogs/TabletAssetDialog.qml index 016deec094..897378e40c 100644 --- a/interface/resources/qml/dialogs/TabletAssetDialog.qml +++ b/interface/resources/qml/dialogs/TabletAssetDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../styles-uit" import "../windows" diff --git a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml index 6d2ff36550..544824135e 100644 --- a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml +++ b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml @@ -10,7 +10,6 @@ import Hifi 1.0 import QtQuick 2.5 -import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs Item { diff --git a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml index 7965006b8b..623388e9b3 100644 --- a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml @@ -8,9 +8,9 @@ // 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 QtQuick 2.7 import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Controls 2.3 import "../controls-uit" import "../styles-uit" @@ -140,12 +140,6 @@ TabletModalWindow { root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth); modalWindowItem.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ? d.maxHeight : targetHeight); - if (checkBoxField.visible && comboBoxField.visible) { - checkBoxField.width = extraInputs.width / 2; - comboBoxField.width = extraInputs.width / 2; - } else if (!checkBoxField.visible && comboBoxField.visible) { - comboBoxField.width = extraInputs.width; - } } } @@ -223,6 +217,15 @@ TabletModalWindow { label: root.comboBox.label; focus: Boolean(root.comboBox); visible: Boolean(root.comboBox); + Binding on x { + when: comboBoxField.visible + value: !checkBoxField.visible ? buttons.x : acceptButton.x + } + + Binding on width { + when: comboBoxField.visible + value: !checkBoxField.visible ? buttons.width : buttons.width - acceptButton.x + } anchors { right: parent.right; bottom: parent.bottom; @@ -294,7 +297,7 @@ TabletModalWindow { Action { id: cancelAction; text: qsTr("Cancel"); - shortcut: Qt.Key_Escape; + shortcut: "Esc"; onTriggered: { root.result = null; root.canceled(); @@ -305,7 +308,7 @@ TabletModalWindow { Action { id: acceptAction; text: qsTr("Add"); - shortcut: Qt.Key_Return; + shortcut: "Return"; onTriggered: { var result = {}; if (textInput) { diff --git a/interface/resources/qml/dialogs/TabletFileDialog.qml b/interface/resources/qml/dialogs/TabletFileDialog.qml index c635095ac6..db15337913 100644 --- a/interface/resources/qml/dialogs/TabletFileDialog.qml +++ b/interface/resources/qml/dialogs/TabletFileDialog.qml @@ -8,12 +8,12 @@ // 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 QtQuick 2.7 import Qt.labs.folderlistmodel 2.1 import Qt.labs.settings 1.0 -import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Controls 1.4 as QQC1 +import QtQuick.Controls 2.3 import ".." import "../controls-uit" @@ -538,7 +538,7 @@ TabletModalWindow { } } - TableViewColumn { + QQC1.TableViewColumn { id: fileNameColumn role: "fileName" title: "Name" @@ -546,7 +546,7 @@ TabletModalWindow { movable: false resizable: true } - TableViewColumn { + QQC1.TableViewColumn { id: fileMofifiedColumn role: "fileModified" title: "Date" @@ -555,7 +555,7 @@ TabletModalWindow { resizable: true visible: !selectDirectory } - TableViewColumn { + QQC1.TableViewColumn { role: "fileSize" title: "Size" width: fileTableView.width - fileNameColumn.width - fileMofifiedColumn.width diff --git a/interface/resources/qml/dialogs/TabletLoginDialog.qml b/interface/resources/qml/dialogs/TabletLoginDialog.qml index 269788a808..c85b2b2ba0 100644 --- a/interface/resources/qml/dialogs/TabletLoginDialog.qml +++ b/interface/resources/qml/dialogs/TabletLoginDialog.qml @@ -10,7 +10,6 @@ import Hifi 1.0 import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../controls-uit" import "../styles-uit" diff --git a/interface/resources/qml/dialogs/TabletMessageBox.qml b/interface/resources/qml/dialogs/TabletMessageBox.qml index f8876b1ec8..fabe0dd247 100644 --- a/interface/resources/qml/dialogs/TabletMessageBox.qml +++ b/interface/resources/qml/dialogs/TabletMessageBox.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import "../controls-uit" diff --git a/interface/resources/qml/dialogs/TabletQueryDialog.qml b/interface/resources/qml/dialogs/TabletQueryDialog.qml index 60dbc106dc..5746a3d67c 100644 --- a/interface/resources/qml/dialogs/TabletQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletQueryDialog.qml @@ -8,9 +8,9 @@ // 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 QtQuick 2.7 import QtQuick.Dialogs 1.2 as OriginalDialogs +import QtQuick.Controls 2.3 import "../controls-uit" import "../styles-uit" @@ -144,7 +144,7 @@ TabletModalWindow { Action { id: cancelAction text: qsTr("Cancel") - shortcut: Qt.Key_Escape + shortcut: "Esc" onTriggered: { root.canceled(); root.destroy(); @@ -153,7 +153,7 @@ TabletModalWindow { Action { id: acceptAction text: qsTr("OK") - shortcut: Qt.Key_Return + shortcut: "Return" onTriggered: { root.result = items ? comboBox.currentText : textResult.text root.selected(root.result); diff --git a/interface/resources/qml/dialogs/assetDialog/+android/AssetDialogContent.qml b/interface/resources/qml/dialogs/assetDialog/+android/AssetDialogContent.qml new file mode 100644 index 0000000000..54bdb0a888 --- /dev/null +++ b/interface/resources/qml/dialogs/assetDialog/+android/AssetDialogContent.qml @@ -0,0 +1,533 @@ +// +// AssetDialogContent.qml +// +// Created by David Rowe on 19 Apr 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.7 +import QtQuick.Controls 1.5 + +import "../../controls-uit" +import "../../styles-uit" + +import "../fileDialog" + +Item { + // Set from OffscreenUi::assetDialog() + property alias dir: assetTableModel.folder + property alias filter: selectionType.filtersString // FIXME: Currently only supports simple filters, "*.xxx". + property int options // Not used. + + property bool selectDirectory: false + + // Not implemented. + //property bool saveDialog: false; + //property bool multiSelect: false; + + property bool singleClickNavigate: false + + HifiConstants { id: hifi } + + Component.onCompleted: { + homeButton.destination = dir; + + if (selectDirectory) { + d.currentSelectionIsFolder = true; + d.currentSelectionPath = assetTableModel.folder; + } + + assetTableView.forceActiveFocus(); + } + + Item { + id: assetDialogItem + anchors.fill: parent + clip: true + + MouseArea { + // Clear selection when click on internal unused area. + anchors.fill: parent + drag.target: root + onClicked: { + d.clearSelection(); + frame.forceActiveFocus(); + assetTableView.forceActiveFocus(); + } + } + + Row { + id: navControls + anchors { + top: parent.top + topMargin: hifi.dimensions.contentMargin.y + left: parent.left + } + spacing: hifi.dimensions.contentSpacing.x + + GlyphButton { + id: upButton + glyph: hifi.glyphs.levelUp + width: height + size: 30 + enabled: assetTableModel.parentFolder !== "" + onClicked: d.navigateUp(); + } + + GlyphButton { + id: homeButton + property string destination: "" + glyph: hifi.glyphs.home + size: 28 + width: height + enabled: destination !== "" + //onClicked: d.navigateHome(); + onClicked: assetTableModel.folder = destination; + } + } + + ComboBox { + id: pathSelector + anchors { + top: parent.top + topMargin: hifi.dimensions.contentMargin.y + left: navControls.right + leftMargin: hifi.dimensions.contentSpacing.x + right: parent.right + } + z: 10 + + property string lastValidFolder: assetTableModel.folder + + function calculatePathChoices(folder) { + var folders = folder.split("/"), + choices = [], + i, length; + + if (folders[folders.length - 1] === "") { + folders.pop(); + } + + choices.push(folders[0]); + + for (i = 1, length = folders.length; i < length; i++) { + choices.push(choices[i - 1] + "/" + folders[i]); + } + + if (folders[0] === "") { + choices[0] = "/"; + } + + choices.reverse(); + + if (choices.length > 0) { + pathSelector.model = choices; + } + } + + onLastValidFolderChanged: { + var folder = lastValidFolder; + calculatePathChoices(folder); + } + + onCurrentTextChanged: { + var folder = currentText; + + if (folder !== "/") { + folder += "/"; + } + + if (folder !== assetTableModel.folder) { + if (root.selectDirectory) { + currentSelection.text = currentText; + d.currentSelectionPath = currentText; + } + assetTableModel.folder = folder; + assetTableView.forceActiveFocus(); + } + } + } + + QtObject { + id: d + + property string currentSelectionPath + property bool currentSelectionIsFolder + property var tableViewConnection: Connections { target: assetTableView; onCurrentRowChanged: d.update(); } + + function update() { + var row = assetTableView.currentRow; + + if (row === -1) { + if (!root.selectDirectory) { + currentSelection.text = ""; + currentSelectionIsFolder = false; + } + return; + } + + var rowInfo = assetTableModel.get(row); + currentSelectionPath = rowInfo.filePath; + currentSelectionIsFolder = rowInfo.fileIsDir; + if (root.selectDirectory || !currentSelectionIsFolder) { + currentSelection.text = currentSelectionPath; + } else { + currentSelection.text = ""; + } + } + + function navigateUp() { + if (assetTableModel.parentFolder !== "") { + assetTableModel.folder = assetTableModel.parentFolder; + return true; + } + return false; + } + + function navigateHome() { + assetTableModel.folder = homeButton.destination; + return true; + } + + function clearSelection() { + assetTableView.selection.clear(); + assetTableView.currentRow = -1; + update(); + } + } + + ListModel { + id: assetTableModel + + property string folder + property string parentFolder: "" + readonly property string rootFolder: "/" + + onFolderChanged: { + parentFolder = calculateParentFolder(); + update(); + } + + function calculateParentFolder() { + if (folder !== "/") { + return folder.slice(0, folder.slice(0, -1).lastIndexOf("/") + 1); + } + return ""; + } + + function isFolder(row) { + if (row === -1) { + return false; + } + return get(row).fileIsDir; + } + + function onGetAllMappings(error, map) { + var mappings, + fileTypeFilter, + index, + path, + fileName, + fileType, + fileIsDir, + isValid, + subDirectory, + subDirectories = [], + fileNameSort, + rows = 0, + lower, + middle, + upper, + i, + length; + + clear(); + + if (error === "") { + mappings = Object.keys(map); + fileTypeFilter = filter.replace("*", "").toLowerCase(); + + for (i = 0, length = mappings.length; i < length; i++) { + index = mappings[i].lastIndexOf("/"); + + path = mappings[i].slice(0, mappings[i].lastIndexOf("/") + 1); + fileName = mappings[i].slice(path.length); + fileType = fileName.slice(fileName.lastIndexOf(".")); + fileIsDir = false; + isValid = false; + + if (fileType.toLowerCase() === fileTypeFilter) { + if (path === folder) { + isValid = !selectDirectory; + } else if (path.length > folder.length) { + subDirectory = path.slice(folder.length); + index = subDirectory.indexOf("/"); + if (index === subDirectory.lastIndexOf("/")) { + fileName = subDirectory.slice(0, index); + if (subDirectories.indexOf(fileName) === -1) { + fileIsDir = true; + isValid = true; + subDirectories.push(fileName); + } + } + } + } + + if (isValid) { + fileNameSort = (fileIsDir ? "*" : "") + fileName.toLowerCase(); + + lower = 0; + upper = rows; + while (lower < upper) { + middle = Math.floor((lower + upper) / 2); + var lessThan; + if (fileNameSort < get(middle)["fileNameSort"]) { + lessThan = true; + upper = middle; + } else { + lessThan = false; + lower = middle + 1; + } + } + + insert(lower, { + fileName: fileName, + filePath: path + (fileIsDir ? "" : fileName), + fileIsDir: fileIsDir, + fileNameSort: fileNameSort + }); + + rows++; + } + } + + } else { + console.log("Error getting mappings from Asset Server"); + } + } + + function update() { + d.clearSelection(); + clear(); + Assets.getAllMappings(onGetAllMappings); + } + } + + Table { + id: assetTableView + colorScheme: hifi.colorSchemes.light + anchors { + top: navControls.bottom + topMargin: hifi.dimensions.contentSpacing.y + left: parent.left + right: parent.right + bottom: currentSelection.top + bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height + } + + model: assetTableModel + + focus: true + + onClicked: { + if (singleClickNavigate) { + navigateToRow(row); + } + } + + onDoubleClicked: navigateToRow(row); + Keys.onReturnPressed: navigateToCurrentRow(); + Keys.onEnterPressed: navigateToCurrentRow(); + + itemDelegate: Item { + clip: true + + FiraSansSemiBold { + text: styleData.value + elide: styleData.elideMode + anchors { + left: parent.left + leftMargin: hifi.dimensions.tablePadding + right: parent.right + rightMargin: hifi.dimensions.tablePadding + verticalCenter: parent.verticalCenter + } + size: hifi.fontSizes.tableText + color: hifi.colors.baseGrayHighlight + font.family: (styleData.row !== -1 && assetTableView.model.get(styleData.row).fileIsDir) + ? "Fira Sans SemiBold" : "Fira Sans" + } + } + + TableViewColumn { + id: fileNameColumn + role: "fileName" + title: "Name" + width: assetTableView.width + movable: false + resizable: false + } + + function navigateToRow(row) { + currentRow = row; + navigateToCurrentRow(); + } + + function navigateToCurrentRow() { + if (model.isFolder(currentRow)) { + model.folder = model.get(currentRow).filePath; + } else { + okAction.trigger(); + } + } + + Timer { + id: prefixClearTimer + interval: 1000 + repeat: false + running: false + onTriggered: assetTableView.prefix = ""; + } + + property string prefix: "" + + function addToPrefix(event) { + if (!event.text || event.text === "") { + return false; + } + var newPrefix = prefix + event.text.toLowerCase(); + var matchedIndex = -1; + for (var i = 0; i < model.count; ++i) { + var name = model.get(i).fileName.toLowerCase(); + if (0 === name.indexOf(newPrefix)) { + matchedIndex = i; + break; + } + } + + if (matchedIndex !== -1) { + assetTableView.selection.clear(); + assetTableView.selection.select(matchedIndex); + assetTableView.currentRow = matchedIndex; + assetTableView.prefix = newPrefix; + } + prefixClearTimer.restart(); + return true; + } + + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Backspace: + case Qt.Key_Tab: + case Qt.Key_Backtab: + event.accepted = false; + break; + + default: + if (addToPrefix(event)) { + event.accepted = true + } else { + event.accepted = false; + } + break; + } + } + } + + TextField { + id: currentSelection + label: selectDirectory ? "Directory:" : "File name:" + anchors { + left: parent.left + right: selectionType.visible ? selectionType.left: parent.right + rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0 + bottom: buttonRow.top + bottomMargin: hifi.dimensions.contentSpacing.y + } + readOnly: true + activeFocusOnTab: !readOnly + onActiveFocusChanged: if (activeFocus) { selectAll(); } + onAccepted: okAction.trigger(); + } + + FileTypeSelection { + id: selectionType + anchors { + top: currentSelection.top + left: buttonRow.left + right: parent.right + } + visible: !selectDirectory && filtersCount > 1 + KeyNavigation.left: assetTableView + KeyNavigation.right: openButton + } + + Action { + id: okAction + text: currentSelection.text && root.selectDirectory && assetTableView.currentRow === -1 ? "Choose" : "Open" + enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false + onTriggered: { + if (!root.selectDirectory && !d.currentSelectionIsFolder + || root.selectDirectory && assetTableView.currentRow === -1) { + selectedAsset(d.currentSelectionPath); + root.destroy(); + } else { + assetTableView.navigateToCurrentRow(); + } + } + } + + Action { + id: cancelAction + text: "Cancel" + onTriggered: { + canceled(); + root.destroy(); + } + } + + Row { + id: buttonRow + anchors { + right: parent.right + bottom: parent.bottom + } + spacing: hifi.dimensions.contentSpacing.y + + Button { + id: openButton + color: hifi.buttons.blue + action: okAction + Keys.onReturnPressed: okAction.trigger() + KeyNavigation.up: selectionType + KeyNavigation.left: selectionType + KeyNavigation.right: cancelButton + } + + Button { + id: cancelButton + action: cancelAction + KeyNavigation.up: selectionType + KeyNavigation.left: openButton + KeyNavigation.right: assetTableView.contentItem + Keys.onReturnPressed: { canceled(); root.enabled = false } + } + } + } + + Keys.onPressed: { + switch (event.key) { + case Qt.Key_Backspace: + event.accepted = d.navigateUp(); + break; + + case Qt.Key_Home: + event.accepted = d.navigateHome(); + break; + + } + } +} diff --git a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml index 84f4c694ff..d49e1e11be 100644 --- a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml +++ b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml @@ -8,8 +8,9 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.3 +import QtQuick.Controls 1.5 as QQC1 import "../../controls-uit" import "../../styles-uit" @@ -362,7 +363,7 @@ Item { } } - TableViewColumn { + QQC1.TableViewColumn { id: fileNameColumn role: "fileName" title: "Name" diff --git a/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml b/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml index bdb42aba61..8411980db7 100644 --- a/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml +++ b/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.2 import QtQuick.Dialogs 1.2 import "../../controls-uit" diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml index 860cbcb5a8..3b3efaf520 100644 --- a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -10,8 +10,6 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "../../controls-uit" as HiFiControls import "../../styles-uit" diff --git a/interface/resources/qml/dialogs/preferences/Preference.qml b/interface/resources/qml/dialogs/preferences/Preference.qml index 1d72197382..6956147950 100644 --- a/interface/resources/qml/dialogs/preferences/Preference.qml +++ b/interface/resources/qml/dialogs/preferences/Preference.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 Item { id: root diff --git a/interface/resources/qml/hifi/ComboDialog.qml b/interface/resources/qml/hifi/ComboDialog.qml index 06254bb7fb..e5dc8a9c1a 100644 --- a/interface/resources/qml/hifi/ComboDialog.qml +++ b/interface/resources/qml/hifi/ComboDialog.qml @@ -10,7 +10,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../styles-uit" import "../controls-uit" diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 8c732aac40..24111ad935 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -1,12 +1,14 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.7 import QtWebEngine 1.5; import Qt.labs.settings 1.0 +import QtQuick.Controls 2.3 + import "../desktop" as OriginalDesktop import ".." import "." import "./toolbars" +import "../controls-uit" OriginalDesktop.Desktop { id: desktop diff --git a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml index ede8590bfb..9e9dcc75b2 100644 --- a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml +++ b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml @@ -10,7 +10,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../styles-uit" Item { diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index 0e9ce89ddb..d88bf1b147 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -10,7 +10,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../styles-uit" Item { diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 3a8559ab1e..4bf80e410b 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -12,8 +12,7 @@ // import Hifi 1.0 as Hifi -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.7 import "../styles-uit" import "../controls-uit" as HifiControlsUit import "../controls" as HifiControls diff --git a/interface/resources/qml/hifi/audio/InputPeak.qml b/interface/resources/qml/hifi/audio/InputPeak.qml index be58c9536b..00f7e63528 100644 --- a/interface/resources/qml/hifi/audio/InputPeak.qml +++ b/interface/resources/qml/hifi/audio/InputPeak.qml @@ -10,8 +10,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 Rectangle { diff --git a/interface/resources/qml/hifi/audio/MicBar.qml b/interface/resources/qml/hifi/audio/MicBar.qml index e798b35e29..fee37ca1c1 100644 --- a/interface/resources/qml/hifi/audio/MicBar.qml +++ b/interface/resources/qml/hifi/audio/MicBar.qml @@ -10,8 +10,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/hifi/audio/PlaySampleSound.qml b/interface/resources/qml/hifi/audio/PlaySampleSound.qml index 6d7eb80974..2b9599a3cc 100644 --- a/interface/resources/qml/hifi/audio/PlaySampleSound.qml +++ b/interface/resources/qml/hifi/audio/PlaySampleSound.qml @@ -9,9 +9,8 @@ // 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 QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import "../../styles-uit" @@ -57,31 +56,31 @@ RowLayout { HifiConstants { id: hifi; } Button { - style: ButtonStyle { - background: Rectangle { - implicitWidth: 20; - implicitHeight: 20; - radius: hifi.buttons.radius; - gradient: Gradient { - GradientStop { - position: 0.2; - color: isPlaying ? hifi.buttons.colorStart[hifi.buttons.blue] : hifi.buttons.colorStart[hifi.buttons.black]; - } - GradientStop { - position: 1.0; - color: isPlaying ? hifi.buttons.colorFinish[hifi.buttons.blue] : hifi.buttons.colorFinish[hifi.buttons.black]; - } + id: control + background: Rectangle { + implicitWidth: 20; + implicitHeight: 20; + radius: hifi.buttons.radius; + gradient: Gradient { + GradientStop { + position: 0.2; + color: isPlaying ? hifi.buttons.colorStart[hifi.buttons.blue] : hifi.buttons.colorStart[hifi.buttons.black]; + } + GradientStop { + position: 1.0; + color: isPlaying ? hifi.buttons.colorFinish[hifi.buttons.blue] : hifi.buttons.colorFinish[hifi.buttons.black]; } } - label: HiFiGlyphs { - // absolutely position due to asymmetry in glyph - x: isPlaying ? 0 : 1; - y: 1; - size: 14; - color: (control.pressed || control.hovered) ? (isPlaying ? "black" : hifi.colors.primaryHighlight) : "white"; - text: isPlaying ? hifi.glyphs.stop_square : hifi.glyphs.playback_play; - } } + contentItem: HiFiGlyphs { + // absolutely position due to asymmetry in glyph +// x: isPlaying ? 0 : 1; +// y: 1; + size: 14; + color: (control.pressed || control.hovered) ? (isPlaying ? "black" : hifi.colors.primaryHighlight) : "white"; + text: isPlaying ? hifi.glyphs.stop_square : hifi.glyphs.playback_play; + } + onClicked: isPlaying ? stopSound() : playSound(); } diff --git a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml index eeda3afc71..89ac9b96e6 100644 --- a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml +++ b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml @@ -14,7 +14,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml index 8105688131..1b77dcd3e9 100644 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml @@ -14,7 +14,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.7 import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml index 9944838e03..5f874d3f04 100644 --- a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml +++ b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml @@ -14,7 +14,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index 009aa8f852..d24344b40a 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -13,7 +13,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index cdcfa4a13e..9f4fc376d4 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -13,7 +13,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml index f6875bb06f..eadf1ca8a2 100644 --- a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml +++ b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml @@ -13,7 +13,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml index e74b0fa9dc..8451c90836 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml @@ -13,7 +13,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index 7c38406697..2ac9015c8c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -13,7 +13,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 5fd6b01d18..e052b78876 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -13,7 +13,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index 224b743c06..216d621bf8 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -14,7 +14,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index 0d7fe9ed18..09b0096638 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -13,7 +13,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml index 85fc0db3be..599c6a1851 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml @@ -13,7 +13,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index b2e7daa066..0edf2865c8 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -14,7 +14,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml index 6956252ee0..44b7ad682c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml @@ -14,7 +14,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls diff --git a/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml b/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml index 76484cf8c7..006a4b7158 100644 --- a/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import Qt.labs.settings 1.0 import "../../styles-uit" diff --git a/interface/resources/qml/hifi/dialogs/AvatarAttachmentsDialog.qml b/interface/resources/qml/hifi/dialogs/AvatarAttachmentsDialog.qml index 5de0864df5..b4357a0077 100644 --- a/interface/resources/qml/hifi/dialogs/AvatarAttachmentsDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AvatarAttachmentsDialog.qml @@ -1,5 +1,5 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.7 +import QtQuick.Controls 1.5 import QtQuick.XmlListModel 2.0 import QtQuick.Controls.Styles 1.4 @@ -104,7 +104,7 @@ ModalWindow { id: acceptAction text: qsTr("OK") enabled: root.result ? true : false - shortcut: Qt.Key_Return + shortcut: "Return" onTriggered: { root.selected(root.result); root.destroy(); @@ -114,7 +114,7 @@ ModalWindow { Action { id: cancelAction text: qsTr("Cancel") - shortcut: Qt.Key_Escape + shortcut: "Esc" onTriggered: { root.canceled(); root.destroy(); diff --git a/interface/resources/qml/hifi/dialogs/ModelBrowserDialog.qml b/interface/resources/qml/hifi/dialogs/ModelBrowserDialog.qml index c427052904..55b4e98bf5 100644 --- a/interface/resources/qml/hifi/dialogs/ModelBrowserDialog.qml +++ b/interface/resources/qml/hifi/dialogs/ModelBrowserDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../windows" import "content" diff --git a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml index 0f363d1be9..1ec7ea3e0e 100644 --- a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml +++ b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import Qt.labs.settings 1.0 import "../../styles-uit" diff --git a/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml b/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml index 22e9dc07a2..50df4dedbc 100644 --- a/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml +++ b/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml @@ -8,8 +8,8 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.2 import Hifi 1.0 as Hifi import "../../styles-uit" @@ -69,9 +69,8 @@ Rectangle { id: textArea width: parent.width height: parent.height - backgroundVisible: false - textColor: hifi.colors.white + background: Item {} + color: hifi.colors.white text:"" } - } diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml index da295917a0..7bce460283 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import Qt.labs.settings 1.0 import "../../styles-uit" diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml index 894a4c1813..d5c5a5ee02 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import Qt.labs.settings 1.0 import "../../styles-uit" import "../../controls-uit" as HifiControls diff --git a/interface/resources/qml/hifi/dialogs/TabletLODTools.qml b/interface/resources/qml/hifi/dialogs/TabletLODTools.qml index 2291a42bf6..ab53f03477 100644 --- a/interface/resources/qml/hifi/dialogs/TabletLODTools.qml +++ b/interface/resources/qml/hifi/dialogs/TabletLODTools.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import Qt.labs.settings 1.0 import "../../styles-uit" import "../../controls-uit" as HifiControls diff --git a/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml b/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml index b6f906ffc2..d93e077b5a 100644 --- a/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml +++ b/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml @@ -1,8 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Dialogs 1.2 as OriginalDialogs -import Qt.labs.settings 1.0 import "." import ".." @@ -184,7 +180,7 @@ Item { decimals: 2; minimumValue: 0.01 maximumValue: 10 - stepSize: 0.05; + realStepSize: 0.05; value: attachment ? attachment.scale : 1.0 colorScheme: hifi.colorSchemes.dark onValueChanged: { diff --git a/interface/resources/qml/hifi/dialogs/attachments/Vector3.qml b/interface/resources/qml/hifi/dialogs/attachments/Vector3.qml index 29f2c0ebf4..228d71fe6f 100644 --- a/interface/resources/qml/hifi/dialogs/attachments/Vector3.qml +++ b/interface/resources/qml/hifi/dialogs/attachments/Vector3.qml @@ -1,5 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControls @@ -57,12 +56,12 @@ Item { colorScheme: hifi.colorSchemes.dark colorLabelInside: hifi.colors.redHighlight decimals: root.decimals - stepSize: root.stepSize + realStepSize: root.stepSize maximumValue: root.maximumValue minimumValue: root.minimumValue - onValueChanged: { - if (value !== vector.x) { - vector.x = value + onRealValueChanged: { + if (realValue !== vector.x) { + vector.x = realValue root.valueChanged(); } } diff --git a/interface/resources/qml/hifi/dialogs/content/AttachmentsContent.qml b/interface/resources/qml/hifi/dialogs/content/AttachmentsContent.qml index 0e0786975e..fa71116574 100644 --- a/interface/resources/qml/hifi/dialogs/content/AttachmentsContent.qml +++ b/interface/resources/qml/hifi/dialogs/content/AttachmentsContent.qml @@ -1,7 +1,6 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.3 import QtQuick.Dialogs 1.2 as OriginalDialogs -import QtQuick.Controls.Styles 1.4 import "../../../styles-uit" import "../../../controls-uit" as HifiControls diff --git a/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml b/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml index 50fca94ff1..ce1abc6154 100644 --- a/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml +++ b/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml @@ -1,5 +1,5 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.3 import "../../../controls-uit" as HifiControls @@ -44,7 +44,7 @@ Column { id: acceptAction text: qsTr("OK") enabled: root.result ? true : false - shortcut: Qt.Key_Return + shortcut: "Return" onTriggered: { root.selected(root.result); root.destroy(); @@ -54,7 +54,7 @@ Column { Action { id: cancelAction text: qsTr("Cancel") - shortcut: Qt.Key_Escape + shortcut: "Esc" onTriggered: { root.canceled(); root.destroy(); diff --git a/interface/resources/qml/hifi/overlays/ImageOverlay.qml b/interface/resources/qml/hifi/overlays/ImageOverlay.qml index cbcf6c7910..f3fbb88c07 100644 --- a/interface/resources/qml/hifi/overlays/ImageOverlay.qml +++ b/interface/resources/qml/hifi/overlays/ImageOverlay.qml @@ -1,5 +1,4 @@ import QtQuick 2.3 -import QtQuick.Controls 1.2 import QtGraphicalEffects 1.0 import "." @@ -20,17 +19,7 @@ Overlay { repeat: false running: false onTriggered: { - if (image.xSize === 0) { - image.xSize = image.sourceSize.width - image.xStart; - } - if (image.ySize === 0) { - image.ySize = image.sourceSize.height - image.yStart; - } - - image.anchors.leftMargin = -image.xStart * root.width / image.xSize; - image.anchors.topMargin = -image.yStart * root.height / image.ySize; - image.anchors.rightMargin = (image.xStart + image.xSize - image.sourceSize.width) * root.width / image.xSize; - image.anchors.bottomMargin = (image.yStart + image.ySize - image.sourceSize.height) * root.height / image.ySize; + recalculateMargins(); } } @@ -44,6 +33,20 @@ Overlay { anchors.fill: parent } + function recalculateMargins() { + if (image.xSize === 0) { + image.xSize = image.sourceSize.width - image.xStart; + } + if (image.ySize === 0) { + image.ySize = image.sourceSize.height - image.yStart; + } + + image.anchors.leftMargin = -image.xStart * root.width / image.xSize; + image.anchors.topMargin = -image.yStart * root.height / image.ySize; + image.anchors.rightMargin = (image.xStart + image.xSize - image.sourceSize.width) * root.width / image.xSize; + image.anchors.bottomMargin = (image.yStart + image.ySize - image.sourceSize.height) * root.height / image.ySize; + } + ColorOverlay { id: color anchors.fill: image @@ -62,6 +65,7 @@ Overlay { case "height": image.ySize = value; break; } } + recalculateMargins(); } function updatePropertiesFromScript(properties) { diff --git a/interface/resources/qml/hifi/overlays/Overlay.qml b/interface/resources/qml/hifi/overlays/Overlay.qml index 80f3233b69..188833bf88 100644 --- a/interface/resources/qml/hifi/overlays/Overlay.qml +++ b/interface/resources/qml/hifi/overlays/Overlay.qml @@ -1,6 +1,5 @@ import Hifi 1.0 import QtQuick 2.3 -import QtQuick.Controls 1.2 Item { id: root diff --git a/interface/resources/qml/hifi/overlays/RectangleOverlay.qml b/interface/resources/qml/hifi/overlays/RectangleOverlay.qml index 514b646c36..d4e70d59d5 100644 --- a/interface/resources/qml/hifi/overlays/RectangleOverlay.qml +++ b/interface/resources/qml/hifi/overlays/RectangleOverlay.qml @@ -1,5 +1,4 @@ import QtQuick 2.3 -import QtQuick.Controls 1.2 import "." diff --git a/interface/resources/qml/hifi/overlays/TextOverlay.qml b/interface/resources/qml/hifi/overlays/TextOverlay.qml index 2fdc9c7cbb..6d7d2e19b5 100644 --- a/interface/resources/qml/hifi/overlays/TextOverlay.qml +++ b/interface/resources/qml/hifi/overlays/TextOverlay.qml @@ -1,5 +1,4 @@ import QtQuick 2.3 -import QtQuick.Controls 1.2 import "." diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml index dd56bc96ab..6c26bd87c5 100644 --- a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -8,11 +8,8 @@ import QtQuick 2.5 - -import QtQuick 2.5 -import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 -import QtQuick.Controls.Styles 1.4 + import "../../styles-uit" import "../../controls" import "../../controls-uit" as HifiControls diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index 4814eaf01c..3e1a7bf139 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -6,8 +6,8 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import "../../styles-uit" import "../../controls" diff --git a/interface/resources/qml/hifi/tablet/Edit.qml b/interface/resources/qml/hifi/tablet/Edit.qml index efd797e12d..4acced86ce 100644 --- a/interface/resources/qml/hifi/tablet/Edit.qml +++ b/interface/resources/qml/hifi/tablet/Edit.qml @@ -1,23 +1,46 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import "../../styles-uit" +import QtQuick 2.7 +import QtQuick.Controls 2.3 StackView { id: editRoot objectName: "stack" - initialItem: Qt.resolvedUrl('EditTabView.qml') signal sendToScript(var message); - HifiConstants { id: hifi } + topPadding: 40 + leftPadding: 0 + rightPadding: 0 + bottomPadding: 0 + + property var itemProperties: {"y": editRoot.topPadding, + "width": editRoot.availableWidth, + "height": editRoot.availableHeight } + Component.onCompleted: { + tab.currentIndex = 0 + } + + background: Rectangle { + color: "#404040" //default background color + EditTabView { + id: tab + anchors.fill: parent + currentIndex: -1 + onCurrentIndexChanged: { + editRoot.replace(null, tab.itemAt(currentIndex).visualItem, + itemProperties, + StackView.Immediate) + } + } + } function pushSource(path) { - editRoot.push(Qt.resolvedUrl("../../" + path)); + editRoot.push(Qt.resolvedUrl("../../" + path), itemProperties, + StackView.Immediate); editRoot.currentItem.sendToScript.connect(editRoot.sendToScript); } function popSource() { - editRoot.pop(); + editRoot.pop(StackView.Immediate); } // Passes script messages to the item on the top of the stack @@ -27,3 +50,4 @@ StackView { currentItem.fromScript(message); } } + diff --git a/interface/resources/qml/hifi/tablet/EditTabButton.qml b/interface/resources/qml/hifi/tablet/EditTabButton.qml new file mode 100644 index 0000000000..13894f4d15 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/EditTabButton.qml @@ -0,0 +1,56 @@ +// +// EditTabButton.qml +// qml/hifi/tablet +// +// Created by Vlad Stelmahovsky on 8/16/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.7 +import QtQuick.Controls 2.2 +import "../../controls-uit" as HifiControls +import "../../styles-uit" + +TabButton { + id: control + property alias title: control.text + property alias active: control.checkable + height: 40 + padding: 0 + spacing: 0 + HifiConstants { id: hifi; } + + contentItem: Text { + id: text + text: control.text + font.pixelSize: 14 + font.bold: true + color: "white" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + fontSizeMode: Text.HorizontalFit + property string glyphtext: "" + HiFiGlyphs { + anchors.centerIn: parent + size: 30 + color: "#ffffff" + text: text.glyphtext + } + Component.onCompleted: { + if (control.text === "P") { + text.text = " "; + text.glyphtext = "\ue004"; + } + } + } + + background: Rectangle { + color: control.checked ? "#404040" :"black" + implicitWidth: control.contentItem.width + 42 > text.paintedWidth ? control.contentItem.width + 42 : + text.paintedWidth + 10 + implicitHeight: 40 + } +} diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index e419b04848..9a7958f95c 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -1,316 +1,286 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls 2.2 // Need both for short-term fix -import QtWebEngine 1.1 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import QtWebChannel 1.0 -import QtQuick.Controls.Styles 1.4 import "../../controls" import "../toolbars" import QtGraphicalEffects 1.0 import "../../controls-uit" as HifiControls import "../../styles-uit" - - -TabView { +TabBar { id: editTabView // anchors.fill: parent - height: 60 + width: parent.width + contentWidth: parent.width + padding: 0 + spacing: 0 - Tab { + readonly property HifiConstants hifi: HifiConstants {} + + EditTabButton { title: "CREATE" active: true enabled: true property string originalUrl: "" - Rectangle { - color: "#404040" - id: container + property Component visualItem: Component { - Flickable { - height: parent.height - width: parent.width + Rectangle { + color: "#404040" + id: container - contentHeight: createEntitiesFlow.height + importButton.height + assetServerButton.height + - header.anchors.topMargin + createEntitiesFlow.anchors.topMargin + - assetServerButton.anchors.topMargin + importButton.anchors.topMargin - contentWidth: width + Flickable { + height: parent.height + width: parent.width + clip: true - ScrollBar.vertical : ScrollBar { - visible: parent.contentHeight > parent.height - width: 20 - background: Rectangle { - color: hifi.colors.tableScrollBackgroundDark - } - } + contentHeight: createEntitiesFlow.height + importButton.height + assetServerButton.height + + header.anchors.topMargin + createEntitiesFlow.anchors.topMargin + + assetServerButton.anchors.topMargin + importButton.anchors.topMargin + + header.paintedHeight - Text { - id: header - color: "#ffffff" - text: "Choose an Entity Type to Create:" - font.pixelSize: 14 - font.bold: true - anchors.top: parent.top - anchors.topMargin: 28 - anchors.left: parent.left - anchors.leftMargin: 28 - } + contentWidth: width - Flow { - id: createEntitiesFlow - spacing: 35 - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: parent.top - anchors.topMargin: 70 + ScrollBar.vertical : ScrollBar { + visible: parent.contentHeight > parent.height + width: 20 + background: Rectangle { + color: hifi.colors.tableScrollBackgroundDark + } + } + + Text { + id: header + color: "#ffffff" + text: "Choose an Entity Type to Create:" + font.pixelSize: 14 + font.bold: true + anchors.top: parent.top + anchors.topMargin: 28 + anchors.left: parent.left + anchors.leftMargin: 28 + } + + Flow { + id: createEntitiesFlow + spacing: 35 + anchors.right: parent.right + anchors.rightMargin: 55 + anchors.left: parent.left + anchors.leftMargin: 55 + anchors.top: parent.top + anchors.topMargin: 70 - NewEntityButton { - icon: "icons/create-icons/94-model-01.svg" - text: "MODEL" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newModelButton" } - }); - editTabView.currentIndex = 2 + NewEntityButton { + icon: "icons/create-icons/94-model-01.svg" + text: "MODEL" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newModelButton" } + }); + editTabView.currentIndex = 2 + } + } + + NewEntityButton { + icon: "icons/create-icons/21-cube-01.svg" + text: "CUBE" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newCubeButton" } + }); + editTabView.currentIndex = 2 + } + } + + NewEntityButton { + icon: "icons/create-icons/22-sphere-01.svg" + text: "SPHERE" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newSphereButton" } + }); + editTabView.currentIndex = 2 + } + } + + NewEntityButton { + icon: "icons/create-icons/24-light-01.svg" + text: "LIGHT" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newLightButton" } + }); + editTabView.currentIndex = 2 + } + } + + NewEntityButton { + icon: "icons/create-icons/20-text-01.svg" + text: "TEXT" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newTextButton" } + }); + editTabView.currentIndex = 2 + } + } + + NewEntityButton { + icon: "icons/create-icons/image.svg" + text: "IMAGE" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newImageButton" } + }); + editTabView.currentIndex = 2 + } + } + + NewEntityButton { + icon: "icons/create-icons/25-web-1-01.svg" + text: "WEB" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newWebButton" } + }); + editTabView.currentIndex = 2 + } + } + + NewEntityButton { + icon: "icons/create-icons/23-zone-01.svg" + text: "ZONE" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newZoneButton" } + }); + editTabView.currentIndex = 2 + } + } + + NewEntityButton { + icon: "icons/create-icons/90-particles-01.svg" + text: "PARTICLE" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newParticleButton" } + }); + editTabView.currentIndex = 4 + } + } + + NewEntityButton { + icon: "icons/create-icons/126-material-01.svg" + text: "MATERIAL" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "newMaterialButton" } + }); + editTabView.currentIndex = 2 + } + } + } + + HifiControls.Button { + id: assetServerButton + text: "Open This Domain's Asset Server" + color: hifi.buttons.black + colorScheme: hifi.colorSchemes.dark + anchors.right: parent.right + anchors.rightMargin: 55 + anchors.left: parent.left + anchors.leftMargin: 55 + anchors.top: createEntitiesFlow.bottom + anchors.topMargin: 35 + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "openAssetBrowserButton" } + }); + } + } + + HifiControls.Button { + id: importButton + text: "Import Entities (.json)" + color: hifi.buttons.black + colorScheme: hifi.colorSchemes.dark + anchors.right: parent.right + anchors.rightMargin: 55 + anchors.left: parent.left + anchors.leftMargin: 55 + anchors.top: assetServerButton.bottom + anchors.topMargin: 20 + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", params: { buttonName: "importEntitiesButton" } + }); + } } } - - NewEntityButton { - icon: "icons/create-icons/21-cube-01.svg" - text: "CUBE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newCubeButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "icons/create-icons/22-sphere-01.svg" - text: "SPHERE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newSphereButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "icons/create-icons/24-light-01.svg" - text: "LIGHT" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newLightButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "icons/create-icons/20-text-01.svg" - text: "TEXT" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newTextButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "icons/create-icons/image.svg" - text: "IMAGE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newImageButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "icons/create-icons/25-web-1-01.svg" - text: "WEB" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newWebButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "icons/create-icons/23-zone-01.svg" - text: "ZONE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newZoneButton" } - }); - editTabView.currentIndex = 2 - } - } - - NewEntityButton { - icon: "icons/create-icons/90-particles-01.svg" - text: "PARTICLE" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newParticleButton" } - }); - editTabView.currentIndex = 4 - } - } - - NewEntityButton { - icon: "icons/create-icons/126-material-01.svg" - text: "MATERIAL" - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "newMaterialButton" } - }); - editTabView.currentIndex = 2 - } - } - } - - HifiControls.Button { - id: assetServerButton - text: "Open This Domain's Asset Server" - color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: createEntitiesFlow.bottom - anchors.topMargin: 35 - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "openAssetBrowserButton" } - }); - } - } - - HifiControls.Button { - id: importButton - text: "Import Entities (.json)" - color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark - anchors.right: parent.right - anchors.rightMargin: 55 - anchors.left: parent.left - anchors.leftMargin: 55 - anchors.top: assetServerButton.bottom - anchors.topMargin: 20 - onClicked: { - editRoot.sendToScript({ - method: "newEntityButtonClicked", params: { buttonName: "importEntitiesButton" } - }); - } - } + } // Flickable } - } // Flickable } - Tab { + EditTabButton { title: "LIST" active: true enabled: true property string originalUrl: "" - WebView { - id: entityListToolWebView - url: Paths.defaultScripts + "/system/html/entityList.html" - anchors.fill: parent - enabled: true + property Component visualItem: Component { + WebView { + id: entityListToolWebView + url: Paths.defaultScripts + "/system/html/entityList.html" + enabled: true + } } } - Tab { + EditTabButton { title: "PROPERTIES" active: true enabled: true property string originalUrl: "" - WebView { - id: entityPropertiesWebView - url: Paths.defaultScripts + "/system/html/entityProperties.html" - anchors.fill: parent - enabled: true + property Component visualItem: Component { + WebView { + id: entityPropertiesWebView + url: Paths.defaultScripts + "/system/html/entityProperties.html" + enabled: true + } } } - Tab { + EditTabButton { title: "GRID" active: true enabled: true property string originalUrl: "" - WebView { - id: gridControlsWebView - url: Paths.defaultScripts + "/system/html/gridControls.html" - anchors.fill: parent - enabled: true + property Component visualItem: Component { + WebView { + id: gridControlsWebView + url: Paths.defaultScripts + "/system/html/gridControls.html" + enabled: true + } } } - Tab { + EditTabButton { title: "P" active: true enabled: true property string originalUrl: "" - WebView { - id: particleExplorerWebView - url: Paths.defaultScripts + "/system/particle_explorer/particleExplorer.html" - anchors.fill: parent - enabled: true - } - } - - - style: TabViewStyle { - frameOverlap: 1 - tab: Rectangle { - color: styleData.selected ? "#404040" :"black" - implicitWidth: text.width + 42 - implicitHeight: 40 - Text { - id: text - anchors.centerIn: parent - text: styleData.title - font.pixelSize: 16 - font.bold: true - color: styleData.selected ? "white" : "white" - property string glyphtext: "" - HiFiGlyphs { - anchors.centerIn: parent - size: 30 - color: "#ffffff" - text: text.glyphtext - } - Component.onCompleted: if (styleData.title == "P") { - text.text = " "; - text.glyphtext = "\ue004"; - } + property Component visualItem: Component { + WebView { + id: particleExplorerWebView + url: Paths.defaultScripts + "/system/particle_explorer/particleExplorer.html" + enabled: true } } - tabBar: Rectangle { - color: "black" - anchors.right: parent.right - anchors.rightMargin: 0 - anchors.left: parent.left - anchors.leftMargin: 0 - anchors.bottom: parent.bottom - anchors.bottomMargin: 0 - anchors.top: parent.top - anchors.topMargin: 0 - } } function fromScript(message) { diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index 292deb751e..527a6cacb4 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -8,8 +8,6 @@ import QtQuick 2.5 import Hifi 1.0 -import QtQuick.Controls 1.4 -import QtQuick.Dialogs 1.2 as OriginalDialogs import "../../styles-uit" import "../../controls-uit" as HifiControls diff --git a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml index c7fbc9d45a..6df97e67b0 100644 --- a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml @@ -9,8 +9,8 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.2 import QtQuick.Dialogs 1.2 as OriginalDialogs import "../../styles-uit" diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index 5216bf45d5..a349653525 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -10,7 +10,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import "../../styles-uit" diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 0978f23013..bd3a95bca0 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -7,10 +7,8 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 -import QtQuick.Controls 1.4 as Original -import QtQuick.Controls.Styles 1.4 + import "../../styles-uit" import "../../controls" import "../../controls-uit" as HifiControls @@ -623,9 +621,6 @@ Rectangle { } } - - - HiFiGlyphs { id: glyphButton color: enabled ? hifi.buttons.textColor[calibrationButton.color] @@ -655,7 +650,6 @@ Rectangle { } } - MouseArea { anchors.fill: parent hoverEnabled: true diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 2da32514cb..dc67494e27 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -9,8 +9,8 @@ // import Hifi 1.0 -import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 import "../../controls" diff --git a/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml b/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml index 19548365aa..7e1cdea0db 100644 --- a/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAttachmentsDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../controls-uit" as HifiControls import "../../styles-uit" diff --git a/interface/resources/qml/hifi/tablet/TabletAudioBuffers.qml b/interface/resources/qml/hifi/tablet/TabletAudioBuffers.qml index 1b4d0feaca..239c2452d4 100644 --- a/interface/resources/qml/hifi/tablet/TabletAudioBuffers.qml +++ b/interface/resources/qml/hifi/tablet/TabletAudioBuffers.qml @@ -8,8 +8,8 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.2 import "tabletWindows" import "../../dialogs" diff --git a/interface/resources/qml/hifi/tablet/TabletAvatarPreferences.qml b/interface/resources/qml/hifi/tablet/TabletAvatarPreferences.qml index 94fb29c6a1..e824036587 100644 --- a/interface/resources/qml/hifi/tablet/TabletAvatarPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletAvatarPreferences.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 +import QtQuick.Controls 2.2 import "tabletWindows" import "../../dialogs" diff --git a/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml b/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml index dee2eed9c3..810f5bb43f 100644 --- a/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletGeneralPreferences.qml @@ -8,8 +8,8 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.2 import "tabletWindows" import "../../dialogs" diff --git a/interface/resources/qml/hifi/tablet/TabletGraphicsPreferences.qml b/interface/resources/qml/hifi/tablet/TabletGraphicsPreferences.qml index 25b5be05f2..3114c79bfe 100644 --- a/interface/resources/qml/hifi/tablet/TabletGraphicsPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletGraphicsPreferences.qml @@ -8,8 +8,8 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.2 import "tabletWindows" import "../../dialogs" diff --git a/interface/resources/qml/hifi/tablet/TabletLodPreferences.qml b/interface/resources/qml/hifi/tablet/TabletLodPreferences.qml index b502c26245..ddc116371d 100644 --- a/interface/resources/qml/hifi/tablet/TabletLodPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletLodPreferences.qml @@ -8,8 +8,8 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.2 import "tabletWindows" import "../../dialogs" diff --git a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml index 520841b33f..74f175e049 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml @@ -10,7 +10,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "../../controls-uit" import "../../styles-uit" diff --git a/interface/resources/qml/hifi/tablet/TabletMenuView.qml b/interface/resources/qml/hifi/tablet/TabletMenuView.qml index 636ebfe71f..2d4d31b9aa 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuView.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuView.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import TabletScriptingInterface 1.0 import "../../styles-uit" diff --git a/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml b/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml index 60bd7a88e0..d69d760b95 100644 --- a/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import "../../controls-uit" as HifiControls import "../../styles-uit" diff --git a/interface/resources/qml/hifi/tablet/TabletNetworkingPreferences.qml b/interface/resources/qml/hifi/tablet/TabletNetworkingPreferences.qml index 91d6140fc3..bad546a39c 100644 --- a/interface/resources/qml/hifi/tablet/TabletNetworkingPreferences.qml +++ b/interface/resources/qml/hifi/tablet/TabletNetworkingPreferences.qml @@ -8,8 +8,8 @@ // 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 QtQuick 2.7 +import QtQuick.Controls 2.2 import "tabletWindows" import "../../dialogs" diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index 8406f23ab2..15db5d8f88 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -1,6 +1,5 @@ import QtQuick 2.0 import Hifi 1.0 -import QtQuick.Controls 1.4 import "../../dialogs" import "../../controls" diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index fcb3e9ff92..a5ef3d2686 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -9,10 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtGraphicalEffects 1.0 - import "." import "./preferences" diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Preference.qml b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Preference.qml index 9986c85445..fcf022c8ef 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Preference.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Preference.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 Item { id: root diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml index 8cf254809d..5036569031 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 import Hifi 1.0 import "../../../../dialogs/preferences" diff --git a/interface/resources/qml/hifi/toolbars/StateImage.qml b/interface/resources/qml/hifi/toolbars/StateImage.qml index ebf1544f2b..9cd311060d 100644 --- a/interface/resources/qml/hifi/toolbars/StateImage.qml +++ b/interface/resources/qml/hifi/toolbars/StateImage.qml @@ -1,5 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 Item { property alias imageURL: image.source diff --git a/interface/resources/qml/hifi/toolbars/Toolbar.qml b/interface/resources/qml/hifi/toolbars/Toolbar.qml index ff7e835690..49aff06929 100644 --- a/interface/resources/qml/hifi/toolbars/Toolbar.qml +++ b/interface/resources/qml/hifi/toolbars/Toolbar.qml @@ -1,5 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 import Qt.labs.settings 1.0 import "../../windows" diff --git a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml index 7781d1140b..232973b4d3 100644 --- a/interface/resources/qml/hifi/toolbars/ToolbarButton.qml +++ b/interface/resources/qml/hifi/toolbars/ToolbarButton.qml @@ -1,5 +1,4 @@ import QtQuick 2.5 -import QtQuick.Controls 1.4 StateImage { id: button diff --git a/interface/resources/qml/styles-uit/AnonymousProRegular.qml b/interface/resources/qml/styles-uit/AnonymousProRegular.qml index d7e13423b6..431ecd0f38 100644 --- a/interface/resources/qml/styles-uit/AnonymousProRegular.qml +++ b/interface/resources/qml/styles-uit/AnonymousProRegular.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 Text { id: root diff --git a/interface/resources/qml/styles-uit/ButtonLabel.qml b/interface/resources/qml/styles-uit/ButtonLabel.qml index aade5fb439..d227cb4869 100644 --- a/interface/resources/qml/styles-uit/ButtonLabel.qml +++ b/interface/resources/qml/styles-uit/ButtonLabel.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewayBold { diff --git a/interface/resources/qml/styles-uit/FiraSansRegular.qml b/interface/resources/qml/styles-uit/FiraSansRegular.qml index 1166fa5cba..05f6ecf74b 100644 --- a/interface/resources/qml/styles-uit/FiraSansRegular.qml +++ b/interface/resources/qml/styles-uit/FiraSansRegular.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 Text { id: root diff --git a/interface/resources/qml/styles-uit/FiraSansSemiBold.qml b/interface/resources/qml/styles-uit/FiraSansSemiBold.qml index 2f095c57a6..32554c2f25 100644 --- a/interface/resources/qml/styles-uit/FiraSansSemiBold.qml +++ b/interface/resources/qml/styles-uit/FiraSansSemiBold.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 Text { id: root diff --git a/interface/resources/qml/styles-uit/IconButton.qml b/interface/resources/qml/styles-uit/IconButton.qml index 84c1ef14c1..e5a18e2ae7 100644 --- a/interface/resources/qml/styles-uit/IconButton.qml +++ b/interface/resources/qml/styles-uit/IconButton.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewayRegular { diff --git a/interface/resources/qml/styles-uit/InfoItem.qml b/interface/resources/qml/styles-uit/InfoItem.qml index 83781a4ef5..fa7684e8e7 100644 --- a/interface/resources/qml/styles-uit/InfoItem.qml +++ b/interface/resources/qml/styles-uit/InfoItem.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewaySemiBold { diff --git a/interface/resources/qml/styles-uit/InputLabel.qml b/interface/resources/qml/styles-uit/InputLabel.qml index 59657a554d..3853dd5b19 100644 --- a/interface/resources/qml/styles-uit/InputLabel.qml +++ b/interface/resources/qml/styles-uit/InputLabel.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewaySemiBold { diff --git a/interface/resources/qml/styles-uit/ListItem.qml b/interface/resources/qml/styles-uit/ListItem.qml index f707686edc..a69c4b48c2 100644 --- a/interface/resources/qml/styles-uit/ListItem.qml +++ b/interface/resources/qml/styles-uit/ListItem.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewayRegular { diff --git a/interface/resources/qml/styles-uit/Logs.qml b/interface/resources/qml/styles-uit/Logs.qml index 577fe2f8d8..45d4436fbf 100644 --- a/interface/resources/qml/styles-uit/Logs.qml +++ b/interface/resources/qml/styles-uit/Logs.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." AnonymousProRegular { diff --git a/interface/resources/qml/styles-uit/OverlayTitle.qml b/interface/resources/qml/styles-uit/OverlayTitle.qml index e23b9eca14..0fb423baab 100644 --- a/interface/resources/qml/styles-uit/OverlayTitle.qml +++ b/interface/resources/qml/styles-uit/OverlayTitle.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewayRegular { diff --git a/interface/resources/qml/styles-uit/RalewayBold.qml b/interface/resources/qml/styles-uit/RalewayBold.qml index 5f42ecd90b..7edde91271 100644 --- a/interface/resources/qml/styles-uit/RalewayBold.qml +++ b/interface/resources/qml/styles-uit/RalewayBold.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 Text { id: root diff --git a/interface/resources/qml/styles-uit/RalewayLight.qml b/interface/resources/qml/styles-uit/RalewayLight.qml index e6b12fca9c..666ebc2ea9 100644 --- a/interface/resources/qml/styles-uit/RalewayLight.qml +++ b/interface/resources/qml/styles-uit/RalewayLight.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 Text { id: root diff --git a/interface/resources/qml/styles-uit/RalewayRegular.qml b/interface/resources/qml/styles-uit/RalewayRegular.qml index 5c9b87dc8a..e263922095 100644 --- a/interface/resources/qml/styles-uit/RalewayRegular.qml +++ b/interface/resources/qml/styles-uit/RalewayRegular.qml @@ -9,8 +9,6 @@ // import QtQuick 2.7 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 Text { id: root diff --git a/interface/resources/qml/styles-uit/RalewaySemiBold.qml b/interface/resources/qml/styles-uit/RalewaySemiBold.qml index 0b25f900bc..19d8b6b8c9 100644 --- a/interface/resources/qml/styles-uit/RalewaySemiBold.qml +++ b/interface/resources/qml/styles-uit/RalewaySemiBold.qml @@ -8,9 +8,7 @@ // 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 QtQuick.Controls.Styles 1.4 +import QtQuick 2.7 Text { id: root diff --git a/interface/resources/qml/styles-uit/SectionName.qml b/interface/resources/qml/styles-uit/SectionName.qml index 5438fec7bc..20f8e1e116 100644 --- a/interface/resources/qml/styles-uit/SectionName.qml +++ b/interface/resources/qml/styles-uit/SectionName.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewayRegular { diff --git a/interface/resources/qml/styles-uit/ShortcutText.qml b/interface/resources/qml/styles-uit/ShortcutText.qml index a3ab351870..8504ffa2b8 100644 --- a/interface/resources/qml/styles-uit/ShortcutText.qml +++ b/interface/resources/qml/styles-uit/ShortcutText.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewayLight { diff --git a/interface/resources/qml/styles-uit/TabName.qml b/interface/resources/qml/styles-uit/TabName.qml index eb4e790e7e..0f620fe8c2 100644 --- a/interface/resources/qml/styles-uit/TabName.qml +++ b/interface/resources/qml/styles-uit/TabName.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." RalewayRegular { diff --git a/interface/resources/qml/styles-uit/TextFieldInput.qml b/interface/resources/qml/styles-uit/TextFieldInput.qml index 010b4d03ad..f2a57e57fc 100644 --- a/interface/resources/qml/styles-uit/TextFieldInput.qml +++ b/interface/resources/qml/styles-uit/TextFieldInput.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import "." FiraSansSemiBold { diff --git a/interface/resources/qml/windows/DefaultFrame.qml b/interface/resources/qml/windows/DefaultFrame.qml index 33c2818849..60e744bec3 100644 --- a/interface/resources/qml/windows/DefaultFrame.qml +++ b/interface/resources/qml/windows/DefaultFrame.qml @@ -9,7 +9,6 @@ // import QtQuick 2.5 -import QtGraphicalEffects 1.0 import "." import "../styles-uit" diff --git a/interface/resources/qml/windows/Fadable.qml b/interface/resources/qml/windows/Fadable.qml index 52d2264e7d..406c6be556 100644 --- a/interface/resources/qml/windows/Fadable.qml +++ b/interface/resources/qml/windows/Fadable.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtGraphicalEffects 1.0 import "../styles-uit" diff --git a/interface/resources/qml/windows/ScrollingWindow.qml b/interface/resources/qml/windows/ScrollingWindow.qml index 1f9b59d2b4..c156b80388 100644 --- a/interface/resources/qml/windows/ScrollingWindow.qml +++ b/interface/resources/qml/windows/ScrollingWindow.qml @@ -10,8 +10,7 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 +import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import "." @@ -39,27 +38,27 @@ Window { property bool keyboardRaised: false property bool punctuationMode: false + readonly property real verticalScrollWidth: 10 + readonly property real verticalScrollShaft: 8 + // Scrollable window content. // FIXME this should not define any visual content in this type. The base window // type should only consist of logic sized areas, with nothing drawn (although the // default value for the frame property does include visual decorations) property var pane: Item { - property bool isScrolling: scrollView.height < scrollView.contentItem.height - property int contentWidth: scrollView.width - (isScrolling ? 10 : 0) + property int contentWidth: scrollView.width property int scrollHeight: scrollView.height anchors.fill: parent - anchors.rightMargin: isScrolling ? 11 : 0 Rectangle { id: contentBackground anchors.fill: parent - anchors.rightMargin: parent.isScrolling ? 11 : 0 + //anchors.rightMargin: parent.isScrolling ? verticalScrollWidth + 1 : 0 color: hifi.colors.baseGray visible: !window.hideBackground && modality != Qt.ApplicationModal } - LinearGradient { visible: !window.hideBackground && gradientsSupported && modality != Qt.ApplicationModal anchors.top: contentBackground.bottom @@ -75,35 +74,28 @@ Window { cached: true } - ScrollView { + Flickable { id: scrollView - contentItem: content - horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - verticalScrollBarPolicy: Qt.ScrollBarAsNeeded + contentItem.children: [ content ] + contentHeight: content.height + boundsBehavior: Flickable.StopAtBounds + property bool isScrolling: (contentHeight - height) > 10 ? true : false + + clip: true + + anchors.rightMargin: isScrolling ? verticalScrollWidth : 0 anchors.fill: parent - anchors.rightMargin: parent.isScrolling ? 1 : 0 anchors.bottomMargin: footerPane.height - style: ScrollViewStyle { - - padding.right: -7 // Move to right away from content. - - handle: Item { - implicitWidth: 8 - Rectangle { - radius: 4 - color: hifi.colors.white30 - anchors { - fill: parent - leftMargin: 2 // Finesse size and position. - topMargin: 1 - bottomMargin: 1 - } - } - } - - scrollBarBackground: Item { - implicitWidth: 10 + ScrollBar.vertical: ScrollBar { + policy: scrollView.isScrolling ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff + parent: scrollView.parent + anchors.top: scrollView.top + anchors.right: scrollView.right + anchors.bottom: scrollView.bottom + anchors.rightMargin: -verticalScrollWidth //compensate scrollview's right margin + background: Item { + implicitWidth: verticalScrollWidth Rectangle { color: hifi.colors.darkGray30 radius: 4 @@ -114,13 +106,18 @@ Window { } } } - - incrementControl: Item { - visible: false - } - - decrementControl: Item { - visible: false + contentItem: Item { + implicitWidth: verticalScrollShaft + Rectangle { + radius: verticalScrollShaft/2 + color: hifi.colors.white30 + anchors { + fill: parent + leftMargin: 2 // Finesse size and position. + topMargin: 1 + bottomMargin: 1 + } + } } } } diff --git a/interface/resources/qml/windows/TabletModalWindow.qml b/interface/resources/qml/windows/TabletModalWindow.qml index e21cb6b224..0dbf4689d6 100644 --- a/interface/resources/qml/windows/TabletModalWindow.qml +++ b/interface/resources/qml/windows/TabletModalWindow.qml @@ -8,9 +8,6 @@ // 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 QtQuick.Dialogs 1.2 as OriginalDialogs -import "." Rectangle { id: modalWindow diff --git a/interface/resources/qml/windows/Window.qml b/interface/resources/qml/windows/Window.qml index 4ed765db4b..835967c628 100644 --- a/interface/resources/qml/windows/Window.qml +++ b/interface/resources/qml/windows/Window.qml @@ -9,8 +9,6 @@ // import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 import "." diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8cba6b1220..9fee772513 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -225,8 +225,8 @@ #ifdef DEBUG_EVENT_QUEUE // This is a HACK that uses private headers included with the qt source distrubution. // To use this feature you need to add these directores to your include path: -// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1/QtCore -// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1 +// E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1/QtCore +// E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1 #define QT_BOOTSTRAPPED #include #include @@ -491,7 +491,7 @@ public: // Don't actually crash in debug builds, in case this apparent deadlock is simply from // the developer actively debugging code #ifdef NDEBUG - deadlockDetectionCrash(); + deadlockDetectionCrash(); #endif } } @@ -774,7 +774,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { steamClient->init(); } - DependencyManager::set(); PROFILE_SET_THREAD_NAME("Main Thread"); #if defined(Q_OS_WIN) @@ -959,10 +958,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::CRASHED, _previousSessionCrashed); - { const QString TEST_SCRIPT = "--testScript"; - const QString TRACE_FILE = "--traceFile"; const QStringList args = arguments(); for (int i = 0; i < args.size() - 1; ++i) { if (args.at(i) == TEST_SCRIPT) { @@ -970,10 +967,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (QFileInfo(testScriptPath).exists()) { setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath)); } - } else if (args.at(i) == TRACE_FILE) { - QString traceFilePath = args.at(i + 1); - setProperty(hifi::properties::TRACING, traceFilePath); - DependencyManager::get()->startTracing(); } } } @@ -1019,6 +1012,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto nodeList = DependencyManager::get(); nodeList->startThread(); + const char** constArgv = const_cast(argv); + if (cmdOptionExists(argc, constArgv, "--disableWatchdog")) { + DISABLE_WATCHDOG = true; + } // Set up a watchdog thread to intentionally crash the application on deadlocks if (!DISABLE_WATCHDOG) { (new DeadlockWatchdogThread())->start(); @@ -1228,7 +1225,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent); connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, &Application::addingEntityWithCertificate); - const char** constArgv = const_cast(argv); QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads"); bool success; int concurrentDownloads = concurrentDownloadsStr.toInt(&success); @@ -2039,7 +2035,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }); _snapshotSound = DependencyManager::get()->getSound(PathUtils::resourcesUrl("sounds/snap.wav")); - + QVariant testProperty = property(hifi::properties::TEST); qDebug() << testProperty; if (testProperty.isValid()) { @@ -6584,7 +6580,7 @@ void Application::addAssetToWorldFromURL(QString url) { } else { filename.remove(".zip"); } - + } if (!DependencyManager::get()->getThisNodeCanWriteAssets()) { @@ -6758,7 +6754,7 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q addAssetToWorldError(filenameFromPath(filePath), errorInfo); } else { // to prevent files that aren't models or texture files from being loaded into world automatically - if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION)) || + if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION)) || ((filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION)) && ((!isBlocks) && (!isZip)))) { addAssetToWorldAddEntity(filePath, mapping); @@ -7407,8 +7403,8 @@ bool Application::isThrottleRendering() const { bool Application::hasFocus() const { bool result = (QApplication::activeWindow() != nullptr); #if defined(Q_OS_WIN) - // On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't - // take user focus away from their current window. So also check whether the application is the user's current foreground + // On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't + // take user focus away from their current window. So also check whether the application is the user's current foreground // window. result = result && (HWND)QApplication::activeWindow()->winId() == GetForegroundWindow(); #endif @@ -7416,7 +7412,7 @@ bool Application::hasFocus() const { } void Application::setFocus() { - // Note: Windows doesn't allow a user focus to be taken away from another application. Instead, it changes the color of and + // Note: Windows doesn't allow a user focus to be taken away from another application. Instead, it changes the color of and // flashes the taskbar icon. auto window = qApp->getWindow(); window->activateWindow(); @@ -7657,7 +7653,7 @@ void Application::updateDisplayMode() { menu->setIsOptionChecked(MenuOption::FirstPerson, true); cameraMenuChanged(); } - + // Remove the mirror camera option from menu if in HMD mode auto mirrorAction = menu->getActionForOption(MenuOption::FullscreenMirror); mirrorAction->setVisible(!isHmd); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6c071defff..df7546cd33 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -447,6 +447,9 @@ Menu::Menu() { textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture512MB, 0, false)); textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture1024MB, 0, false)); textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture2048MB, 0, false)); + textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture4096MB, 0, false)); + textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture6144MB, 0, false)); + textureGroup->addAction(addCheckableActionToQMenuAndActionHash(textureMenu, MenuOption::RenderMaxTexture8192MB, 0, false)); connect(textureGroup, &QActionGroup::triggered, [textureGroup] { auto checked = textureGroup->checkedAction(); auto text = checked->text(); @@ -463,6 +466,12 @@ Menu::Menu() { newMaxTextureMemory = MB_TO_BYTES(1024); } else if (MenuOption::RenderMaxTexture2048MB == text) { newMaxTextureMemory = MB_TO_BYTES(2048); + } else if (MenuOption::RenderMaxTexture4096MB == text) { + newMaxTextureMemory = MB_TO_BYTES(4096); + } else if (MenuOption::RenderMaxTexture6144MB == text) { + newMaxTextureMemory = MB_TO_BYTES(6144); + } else if (MenuOption::RenderMaxTexture8192MB == text) { + newMaxTextureMemory = MB_TO_BYTES(8192); } gpu::Texture::setAllowedGPUMemoryUsage(newMaxTextureMemory); }); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index cf9eed1a27..4d418a16d2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -155,6 +155,10 @@ namespace MenuOption { const QString RenderMaxTexture512MB = "512 MB"; const QString RenderMaxTexture1024MB = "1024 MB"; const QString RenderMaxTexture2048MB = "2048 MB"; + const QString RenderMaxTexture3072MB = "3072 MB"; + const QString RenderMaxTexture4096MB = "4096 MB"; + const QString RenderMaxTexture6144MB = "6144 MB"; + const QString RenderMaxTexture8192MB = "8192 MB"; const QString RenderResolution = "Scale Resolution"; const QString RenderResolutionOne = "1"; const QString RenderResolutionTwoThird = "2/3"; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 118f14e71b..6f82c7dfb9 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -299,7 +299,7 @@ public: * (such as look at vectors, hand sensors etc.). Each animation specified in the avatar-animation.json file is known as an animation role. * Animation roles map to easily understandable actions that the avatar can perform, such as "idleStand", "idleTalk", or "walkFwd." * getAnimationRoles() is used get the list of animation roles defined in the avatar-animation.json. - * @function MyAvatar.getAnimatationRoles + * @function MyAvatar.getAnimationRoles * @example This example prints the list of animation roles defined in the avatar's avatar-animation.json file to the debug log. * var roles = MyAvatar.getAnimationRoles(); * print("Animation Roles:"); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 51ec4b1327..22db128f7e 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -31,6 +31,8 @@ #include "UserActivityLogger.h" #include "MainWindow.h" +#include "Profile.h" + #ifdef Q_OS_WIN extern "C" { typedef int(__stdcall * CHECKMINSPECPROC) (); @@ -40,6 +42,26 @@ extern "C" { int main(int argc, const char* argv[]) { setupHifiApplication(BuildInfo::INTERFACE_NAME); + // Early check for --traceFile argument + auto tracer = DependencyManager::set(); + const char * traceFile = nullptr; + const QString traceFileFlag("--traceFile"); + float traceDuration = 0.0f; + for (int a = 1; a < argc; ++a) { + if (traceFileFlag == argv[a] && argc > a + 1) { + traceFile = argv[a + 1]; + if (argc > a + 2) { + traceDuration = atof(argv[a + 2]); + } + break; + } + } + if (traceFile != nullptr) { + tracer->startTracing(); + } + + PROFILE_SYNC_BEGIN(startup, "main startup", ""); + #ifdef Q_OS_LINUX QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar); #endif @@ -235,7 +257,18 @@ int main(int argc, const char* argv[]) { argvExtended.push_back("--ignore-gpu-blacklist"); int argcExtended = (int)argvExtended.size(); + PROFILE_SYNC_END(startup, "main startup", ""); + PROFILE_SYNC_BEGIN(startup, "app full ctor", ""); Application app(argcExtended, const_cast(argvExtended.data()), startupTime, runningMarkerExisted); + PROFILE_SYNC_END(startup, "app full ctor", ""); + + + QTimer exitTimer; + if (traceDuration > 0.0f) { + exitTimer.setSingleShot(true); + QObject::connect(&exitTimer, &QTimer::timeout, &app, &Application::quit); + exitTimer.start(int(1000 * traceDuration)); + } #if 0 // If we failed the OpenGLVersion check, log it. @@ -273,6 +306,11 @@ int main(int argc, const char* argv[]) { qCDebug(interfaceapp, "Created QT Application."); exitCode = app.exec(); server.close(); + + if (traceFile != nullptr) { + tracer->stopTracing(); + tracer->serialize(QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/" + traceFile); + } } Application::shutdownPlugins(); diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 74a15db0ce..9e7c0e142e 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -156,3 +156,7 @@ void TestScriptingInterface::profileRange(const QString& name, QScriptValue fn) fn.call(); } +void TestScriptingInterface::clearCaches() { + qApp->reloadResourceCaches(); +} + diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index aca07d110b..687cb41689 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -78,6 +78,11 @@ public slots: Q_INVOKABLE void profileRange(const QString& name, QScriptValue function); + /**jsdoc + * Clear all caches (menu command Reload Content) + */ + void clearCaches(); + private: bool waitForCondition(qint64 maxWaitMs, std::function condition); }; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 1c00f57eec..7edc03490c 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -35,7 +35,19 @@ ModelOverlay::ModelOverlay(const ModelOverlay* modelOverlay) : _url(modelOverlay->_url), _updateModel(false), _scaleToFit(modelOverlay->_scaleToFit), - _loadPriority(modelOverlay->_loadPriority) + _loadPriority(modelOverlay->_loadPriority), + + _animationURL(modelOverlay->_animationURL), + _animationFPS(modelOverlay->_animationFPS), + _animationCurrentFrame(modelOverlay->_animationCurrentFrame), + _animationRunning(modelOverlay->_animationRunning), + _animationLoop(modelOverlay->_animationLoop), + _animationFirstFrame(modelOverlay->_animationFirstFrame), + _animationLastFrame(modelOverlay->_animationLastFrame), + _animationHold(modelOverlay->_animationHold), + _animationAllowTranslation(modelOverlay->_animationAllowTranslation) + + // Joint translations and rotations aren't copied because the model needs to load before they can be applied. { _model->setLoadingPriority(_loadPriority); if (_url.isValid()) { @@ -341,20 +353,25 @@ vectorType ModelOverlay::mapJoints(mapFunction function) const { * parentID is an avatar skeleton. A value of 65535 means "no joint". * * @property {string} url - The URL of the FBX or OBJ model used for the overlay. + * @property {number} loadPriority=0.0 - The priority for loading and displaying the overlay. Overlays with higher values load + * first. * @property {Vec3} dimensions - The dimensions of the overlay. Synonym: size. * @property {Vec3} scale - The scale factor applied to the model's dimensions. * @property {object.} textures - Maps the named textures in the model to the JPG or PNG images in the urls. - * @property {Array.} jointNames - The names of the joints - if any - in the model. Read-only - * @property {Array.} jointRotations - The relative rotations of the model's joints. - * @property {Array.} jointTranslations - The relative translations of the model's joints. + * @property {Array.} jointNames - The names of the joints - if any - in the model. Read-only. + * @property {Array.} jointRotations - The relative rotations of the model's joints. Not copied if overlay is + * cloned. + * @property {Array.} jointTranslations - The relative translations of the model's joints. Not copied if overlay is + * cloned. * @property {Array.} jointOrientations - The absolute orientations of the model's joints, in world coordinates. - * Read-only + * Read-only. * @property {Array.} jointPositions - The absolute positions of the model's joints, in world coordinates. - * Read-only + * Read-only. * @property {string} animationSettings.url="" - The URL of an FBX file containing an animation to play. * @property {number} animationSettings.fps=0 - The frame rate (frames/sec) to play the animation at. * @property {number} animationSettings.firstFrame=0 - The frame to start playing at. * @property {number} animationSettings.lastFrame=0 - The frame to finish playing at. + * @property {number} animationSettings.currentFrame=0 - The current frame being played. * @property {boolean} animationSettings.running=false - Whether or not the animation is playing. * @property {boolean} animationSettings.loop=false - Whether or not the animation should repeat in a loop. * @property {boolean} animationSettings.hold=false - Whether or not when the animation finishes, the rotations and @@ -384,6 +401,10 @@ QVariant ModelOverlay::getProperty(const QString& property) { } } + if (property == "loadPriority") { + return _loadPriority; + } + if (property == "jointNames") { if (_model && _model->isActive()) { // note: going through Rig because Model::getJointNames() (which proxies to FBXGeometry) was always empty diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1bbc8cc1a5..08eee947ef 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2058,24 +2058,34 @@ static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities"); static const QString JSON_AVATAR_SCALE = QStringLiteral("scale"); static const QString JSON_AVATAR_VERSION = QStringLiteral("version"); -static const int JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION = 0; -static const int JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION = 1; +enum class JsonAvatarFrameVersion : int { + JointRotationsInRelativeFrame = 0, + JointRotationsInAbsoluteFrame, + JointDefaultPoseBits +}; QJsonValue toJsonValue(const JointData& joint) { QJsonArray result; result.push_back(toJsonValue(joint.rotation)); result.push_back(toJsonValue(joint.translation)); + result.push_back(QJsonValue(joint.rotationIsDefaultPose)); + result.push_back(QJsonValue(joint.translationIsDefaultPose)); return result; } -JointData jointDataFromJsonValue(const QJsonValue& json) { +JointData jointDataFromJsonValue(int version, const QJsonValue& json) { JointData result; if (json.isArray()) { QJsonArray array = json.toArray(); result.rotation = quatFromJsonValue(array[0]); - result.rotationIsDefaultPose = false; result.translation = vec3FromJsonValue(array[1]); - result.translationIsDefaultPose = false; + if (version >= (int)JsonAvatarFrameVersion::JointDefaultPoseBits) { + result.rotationIsDefaultPose = array[2].toBool(); + result.translationIsDefaultPose = array[3].toBool(); + } else { + result.rotationIsDefaultPose = false; + result.translationIsDefaultPose = false; + } } return result; } @@ -2083,7 +2093,7 @@ JointData jointDataFromJsonValue(const QJsonValue& json) { QJsonObject AvatarData::toJson() const { QJsonObject root; - root[JSON_AVATAR_VERSION] = JSON_AVATAR_JOINT_ROTATIONS_IN_ABSOLUTE_FRAME_VERSION; + root[JSON_AVATAR_VERSION] = (int)JsonAvatarFrameVersion::JointDefaultPoseBits; if (!getSkeletonModelURL().isEmpty()) { root[JSON_AVATAR_BODY_MODEL] = getSkeletonModelURL().toString(); @@ -2158,7 +2168,7 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { version = json[JSON_AVATAR_VERSION].toInt(); } else { // initial data did not have a version field. - version = JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION; + version = (int)JsonAvatarFrameVersion::JointRotationsInRelativeFrame; } if (json.contains(JSON_AVATAR_BODY_MODEL)) { @@ -2235,7 +2245,7 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { // } if (json.contains(JSON_AVATAR_JOINT_ARRAY)) { - if (version == JSON_AVATAR_JOINT_ROTATIONS_IN_RELATIVE_FRAME_VERSION) { + if (version == (int)JsonAvatarFrameVersion::JointRotationsInRelativeFrame) { // because we don't have the full joint hierarchy skeleton of the model, // we can't properly convert from relative rotations into absolute rotations. quint64 now = usecTimestampNow(); @@ -2247,7 +2257,7 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { QJsonArray jointArrayJson = json[JSON_AVATAR_JOINT_ARRAY].toArray(); jointArray.reserve(jointArrayJson.size()); for (const auto& jointJson : jointArrayJson) { - auto joint = jointDataFromJsonValue(jointJson); + auto joint = jointDataFromJsonValue(version, jointJson); jointArray.push_back(joint); } setRawJointData(jointArray); @@ -2558,4 +2568,4 @@ void AvatarEntityMapFromScriptValue(const QScriptValue& object, AvatarEntityMap& value[EntityID] = binaryEntityProperties; } -} \ No newline at end of file +} diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 2c60ca25f5..fbc87898a4 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -96,9 +96,9 @@ namespace controller { Q_INVOKABLE QObject* parseMapping(const QString& json); Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl); - Q_INVOKABLE const QVariantMap& getHardware() { return _hardware; } - Q_INVOKABLE const QVariantMap& getActions() { return _actions; } - Q_INVOKABLE const QVariantMap& getStandard() { return _standard; } + Q_INVOKABLE const QVariantMap getHardware() { return _hardware; } + Q_INVOKABLE const QVariantMap getActions() { return _actions; } + Q_INVOKABLE const QVariantMap getStandard() { return _standard; } Q_INVOKABLE void startInputRecording(); Q_INVOKABLE void stopInputRecording(); Q_INVOKABLE void startInputPlayback(); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index ea8edb8a08..7cea841bf0 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -18,7 +18,7 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP if (entity->getMaterial() != _drawMaterial) { return true; } - if (entity->getParentID() != _parentID || entity->getClientOnly() != _clientOnly || entity->getOwningAvatarID() != _owningAvatarID) { + if (entity->getParentID() != _parentID) { return true; } if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) { @@ -31,8 +31,6 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& withWriteLock([&] { _drawMaterial = entity->getMaterial(); _parentID = entity->getParentID(); - _clientOnly = entity->getClientOnly(); - _owningAvatarID = entity->getOwningAvatarID(); _materialMappingPos = entity->getMaterialMappingPos(); _materialMappingScale = entity->getMaterialMappingScale(); _materialMappingRot = entity->getMaterialMappingRot(); @@ -102,7 +100,7 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { graphics::MaterialPointer drawMaterial; Transform textureTransform; withReadLock([&] { - parentID = _clientOnly ? _owningAvatarID : _parentID; + parentID = _parentID; renderTransform = _renderTransform; drawMaterial = _drawMaterial; textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0)); diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index 8de2190a0c..96c720f79f 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -32,8 +32,6 @@ private: ShapeKey getShapeKey() override; QUuid _parentID; - bool _clientOnly; - QUuid _owningAvatarID; glm::vec2 _materialMappingPos; glm::vec2 _materialMappingScale; float _materialMappingRot; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index aab8777862..8a87a98a10 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -62,7 +62,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : EntityItem::~EntityItem() { // these pointers MUST be correct at delete, else we probably have a dangling backpointer // to this EntityItem in the corresponding data structure. - assert(!_simulated); + assert(!_simulated || (!_element && !_physicsInfo)); assert(!_element); assert(!_physicsInfo); } @@ -693,7 +693,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // the entity-server is awarding us ownership which is what we want _simulationOwner.set(newSimOwner); } - } else if (newSimOwner.matchesValidID(myNodeID) && !_hasBidOnSimulation) { + } else if (newSimOwner.matchesValidID(myNodeID) && !_simulationOwner.pendingTake(now)) { // entity-server tells us that we have simulation ownership while we never requested this for this EntityItem, // this could happen when the user reloads the cache and entity tree. markDirtyFlags(Simulation::DIRTY_SIMULATOR_ID); @@ -1946,10 +1946,6 @@ void EntityItem::setPendingOwnershipPriority(uint8_t priority, const quint64& ti _simulationOwner.setPendingPriority(priority, timestamp); } -void EntityItem::rememberHasSimulationOwnershipBid() const { - _hasBidOnSimulation = true; -} - QString EntityItem::actionsToDebugString() { QString result; QVector serializedActions; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ebbeaaa254..de98c1a47a 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -58,6 +58,9 @@ using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr getMaterials(); + void setSimulationOwnershipExpiry(uint64_t expiry) { _simulationOwnershipExpiry = expiry; } + uint64_t getSimulationOwnershipExpiry() const { return _simulationOwnershipExpiry; } + signals: void requestRenderUpdate(); @@ -619,9 +625,6 @@ protected: static quint64 _rememberDeletedActionTime; mutable QHash _previouslyDeletedActions; - // per entity keep state if it ever bid on simulation, so that we can ignore false simulation ownership - mutable bool _hasBidOnSimulation { false }; - QUuid _sourceUUID; /// the server node UUID we came from bool _clientOnly { false }; @@ -642,6 +645,7 @@ protected: quint64 _lastUpdatedAngularVelocityTimestamp { 0 }; quint64 _lastUpdatedAccelerationTimestamp { 0 }; quint64 _lastUpdatedQueryAACubeTimestamp { 0 }; + uint64_t _simulationOwnershipExpiry { 0 }; bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f9a96d2293..8b916a875f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -363,6 +363,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_POS, materialMappingPos); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale); CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot); + CHECK_PROPERTY_CHANGE(PROP_MATERIAL_DATA, materialData); // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); @@ -1208,6 +1209,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); // Certifiable Properties COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ITEM_NAME, itemName); @@ -1252,7 +1254,6 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_SPREAD, colorSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_START, colorStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLOR_FINISH, colorFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); @@ -1376,6 +1377,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_POS, materialMappingPos); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_DATA, materialData); } /**jsdoc @@ -1539,6 +1541,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingPos, glmVec2, setMaterialMappingPos); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, glmVec2, setMaterialMappingScale); COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot); + COPY_PROPERTY_FROM_QSCRIPTVALUE(materialData, QString, setMaterialData); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1902,6 +1905,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glmVec2); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glmVec2); ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float); + ADD_PROPERTY_TO_MAP(PROP_MATERIAL_DATA, MaterialData, materialData, QString); // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); @@ -2298,6 +2302,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, properties.getMaterialMappingPos()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, properties.getMaterialMappingScale()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, properties.getMaterialMappingRot()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_DATA, properties.getMaterialData()); } APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); @@ -2666,6 +2671,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_POS, glmVec2, setMaterialMappingPos); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_SCALE, glmVec2, setMaterialMappingScale); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_DATA, QString, setMaterialData); } READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); @@ -2849,6 +2855,7 @@ void EntityItemProperties::markAllChanged() { _materialMappingPosChanged = true; _materialMappingScaleChanged = true; _materialMappingRotChanged = true; + _materialDataChanged = true; // Certifiable Properties _itemNameChanged = true; @@ -3200,6 +3207,9 @@ QList EntityItemProperties::listChangedProperties() { if (materialMappingRotChanged()) { out += "materialMappingRot"; } + if (materialDataChanged()) { + out += "materialData"; + } // Certifiable Properties if (itemNameChanged()) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index cc832146e8..38e4f0c8c0 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -230,6 +230,7 @@ public: DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glmVec2, glm::vec2(0, 0)); DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glmVec2, glm::vec2(1, 1)); DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float, 0); + DEFINE_PROPERTY_REF(PROP_MATERIAL_DATA, MaterialData, materialData, QString, ""); // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 07908fe6cf..99a5f287ea 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -240,6 +240,7 @@ enum EntityPropertyList { PROP_MATERIAL_MAPPING_POS, PROP_MATERIAL_MAPPING_SCALE, PROP_MATERIAL_MAPPING_ROT, + PROP_MATERIAL_DATA, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index c80eb0b78f..58898216fa 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -241,14 +241,18 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties _activityTracking.addedEntityCount++; + auto nodeList = DependencyManager::get(); + auto sessionID = nodeList->getSessionUUID(); + EntityItemProperties propertiesWithSimID = properties; if (clientOnly) { - auto nodeList = DependencyManager::get(); - const QUuid myNodeID = nodeList->getSessionUUID(); + const QUuid myNodeID = sessionID; propertiesWithSimID.setClientOnly(clientOnly); propertiesWithSimID.setOwningAvatarID(myNodeID); } + propertiesWithSimID.setLastEditedBy(sessionID); + bool scalesWithParent = propertiesWithSimID.getScalesWithParent(); propertiesWithSimID = convertPropertiesFromScriptSemantics(propertiesWithSimID, scalesWithParent); @@ -308,6 +312,11 @@ QUuid EntityScriptingInterface::addModelEntity(const QString& name, const QStrin if (!textures.isEmpty()) { properties.setTextures(textures); } + + auto nodeList = DependencyManager::get(); + auto sessionID = nodeList->getSessionUUID(); + properties.setLastEditedBy(sessionID); + return addEntity(properties); } @@ -363,7 +372,11 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& _activityTracking.editedEntityCount++; + auto nodeList = DependencyManager::get(); + auto sessionID = nodeList->getSessionUUID(); + EntityItemProperties properties = scriptSideProperties; + properties.setLastEditedBy(sessionID); EntityItemID entityID(id); if (!_entityTree) { @@ -379,7 +392,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& return; } - auto nodeList = DependencyManager::get(); if (entity->getClientOnly() && entity->getOwningAvatarID() != nodeList->getSessionUUID()) { // don't edit other avatar's avatarEntities return; @@ -454,7 +466,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& // we make a bid for simulation ownership properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY); entity->flagForOwnershipBid(SCRIPT_POKE_SIMULATION_PRIORITY); - entity->rememberHasSimulationOwnershipBid(); } } if (properties.queryAACubeRelatedPropertyChanged()) { diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 7f6a7087cf..9c7b46dc17 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -370,12 +370,18 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti simulationBlocked = false; } } + if (!simulationBlocked) { + entity->setSimulationOwnershipExpiry(usecTimestampNow() + MAX_INCOMING_SIMULATION_UPDATE_PERIOD); + } } else { // the entire update is suspect --> ignore it return false; } } else if (simulationBlocked) { simulationBlocked = senderID != entity->getSimulatorID(); + if (!simulationBlocked) { + entity->setSimulationOwnershipExpiry(usecTimestampNow() + MAX_INCOMING_SIMULATION_UPDATE_PERIOD); + } } if (simulationBlocked) { // squash ownership and physics-related changes. @@ -1149,7 +1155,9 @@ void EntityTree::startChallengeOwnershipTimer(const EntityItemID& entityItemID) }); connect(_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() { qCDebug(entities) << "Ownership challenge timed out, deleting entity" << entityItemID; - deleteEntity(entityItemID, true); + withWriteLock([&] { + deleteEntity(entityItemID, true); + }); if (_challengeOwnershipTimeoutTimer) { _challengeOwnershipTimeoutTimer->stop(); _challengeOwnershipTimeoutTimer->deleteLater(); @@ -1257,7 +1265,9 @@ void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QStri if (text == "") { qCDebug(entities) << "CRITICAL ERROR: Couldn't compute nonce. Deleting entity..."; - deleteEntity(entityItemID, true); + withWriteLock([&] { + deleteEntity(entityItemID, true); + }); } else { qCDebug(entities) << "Challenging ownership of Cert ID" << certID; // 2. Send the nonce to the rezzing avatar's node @@ -1320,8 +1330,7 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt request["certificate_id"] = certID; networkRequest.setUrl(requestURL); - QNetworkReply* networkReply = NULL; - networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); + QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); connect(networkReply, &QNetworkReply::finished, [=]() { QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); @@ -1330,14 +1339,20 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt if (networkReply->error() == QNetworkReply::NoError) { if (!jsonObject["invalid_reason"].toString().isEmpty()) { qCDebug(entities) << "invalid_reason not empty, deleting entity" << entityItemID; - deleteEntity(entityItemID, true); + withWriteLock([&] { + deleteEntity(entityItemID, true); + }); } else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") { qCDebug(entities) << "'transfer_status' is 'failed', deleting entity" << entityItemID; - deleteEntity(entityItemID, true); + withWriteLock([&] { + deleteEntity(entityItemID, true); + }); } else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") { if (isRetryingValidation) { qCDebug(entities) << "'transfer_status' is 'pending' after retry, deleting entity" << entityItemID; - deleteEntity(entityItemID, true); + withWriteLock([&] { + deleteEntity(entityItemID, true); + }); } else { if (thread() != QThread::currentThread()) { QMetaObject::invokeMethod(this, "startPendingTransferStatusTimer", @@ -1360,7 +1375,9 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt } else { qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << entityItemID << "More info:" << jsonObject; - deleteEntity(entityItemID, true); + withWriteLock([&] { + deleteEntity(entityItemID, true); + }); } networkReply->deleteLater(); @@ -1794,9 +1811,9 @@ void EntityTree::addToNeedsParentFixupList(EntityItemPointer entity) { void EntityTree::update(bool simulate) { PROFILE_RANGE(simulation_physics, "UpdateTree"); - fixupNeedsParentFixups(); - if (simulate && _simulation) { - withWriteLock([&] { + withWriteLock([&] { + fixupNeedsParentFixups(); + if (simulate && _simulation) { _simulation->updateEntities(); { PROFILE_RANGE(simulation_physics, "Deletes"); @@ -1814,8 +1831,8 @@ void EntityTree::update(bool simulate) { deleteEntities(idsToDelete, true); } } - }); - } + } + }); } quint64 EntityTree::getAdjustedConsiderSince(quint64 sinceTime) { @@ -2284,7 +2301,9 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer QScriptEngine scriptEngine; RecurseOctreeToMapOperator theOperator(entityDescription, element, &scriptEngine, skipDefaultValues, skipThoseWithBadParents, _myAvatar); - recurseTreeWithOperator(&theOperator); + withReadLock([&] { + recurseTreeWithOperator(&theOperator); + }); return true; } @@ -2376,6 +2395,30 @@ bool EntityTree::readFromMap(QVariantMap& map) { } } + // Convert old materials so that they use materialData instead of userData + if (contentVersion < (int)EntityVersion::MaterialData && properties.getType() == EntityTypes::EntityType::Material) { + if (properties.getMaterialURL().startsWith("userData")) { + QString materialURL = properties.getMaterialURL(); + properties.setMaterialURL(materialURL.replace("userData", "materialData")); + + QJsonObject userData = QJsonDocument::fromJson(properties.getUserData().toUtf8()).object(); + QJsonObject materialData; + QJsonValue materialVersion = userData["materialVersion"]; + if (!materialVersion.isNull()) { + materialData.insert("materialVersion", materialVersion); + userData.remove("materialVersion"); + } + QJsonValue materials = userData["materials"]; + if (!materials.isNull()) { + materialData.insert("materials", materials); + userData.remove("materials"); + } + + properties.setMaterialData(QJsonDocument(materialData).toJson()); + properties.setUserData(QJsonDocument(userData).toJson()); + } + } + EntityItemPointer entity = addEntity(entityItemID, properties); if (!entity) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index b219d64d9d..a56af5d03f 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -243,14 +243,10 @@ public: return std::static_pointer_cast(shared_from_this()); } - void bumpChangedContent() { _lastChangedContent = usecTimestampNow(); } - uint64_t getLastChangedContent() const { return _lastChangedContent; } - protected: virtual void init(unsigned char * octalCode) override; EntityTreePointer _myTree; EntityItems _entityItems; - uint64_t _lastChangedContent { 0 }; }; #endif // hifi_EntityTreeElement_h diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp index 8b595bf69d..6c040296a3 100644 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ b/libraries/entities/src/MaterialEntityItem.cpp @@ -27,6 +27,10 @@ MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : Entit _type = EntityTypes::Material; } +MaterialEntityItem::~MaterialEntityItem() { + removeMaterial(); +} + EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL); @@ -36,6 +40,7 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingPos, getMaterialMappingPos); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingScale, getMaterialMappingScale); COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingRot, getMaterialMappingRot); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialData, getMaterialData); return properties; } @@ -49,6 +54,7 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingPos, setMaterialMappingPos); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingScale, setMaterialMappingScale); SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingRot, setMaterialMappingRot); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialData, setMaterialData); if (somethingChanged) { bool wantDebug = false; @@ -78,6 +84,7 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, glm::vec2, setMaterialMappingPos); READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, glm::vec2, setMaterialMappingScale); READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot); + READ_ENTITY_PROPERTY(PROP_MATERIAL_DATA, QString, setMaterialData); return bytesRead; } @@ -93,6 +100,7 @@ EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParam requestedProperties += PROP_MATERIAL_MAPPING_POS; requestedProperties += PROP_MATERIAL_MAPPING_SCALE; requestedProperties += PROP_MATERIAL_MAPPING_ROT; + requestedProperties += PROP_MATERIAL_DATA; return requestedProperties; } @@ -112,6 +120,7 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, getMaterialMappingPos()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, getMaterialMappingScale()); APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, getMaterialMappingRot()); + APPEND_ENTITY_PROPERTY(PROP_MATERIAL_DATA, getMaterialData()); } void MaterialEntityItem::debugDump() const { @@ -145,9 +154,9 @@ std::shared_ptr MaterialEntityItem::getMaterial() const { } } -void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool userDataChanged) { - bool usingUserData = materialURLString.startsWith("userData"); - if (_materialURL != materialURLString || (usingUserData && userDataChanged)) { +void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool materialDataChanged) { + bool usingMaterialData = materialDataChanged || materialURLString.startsWith("materialData"); + if (_materialURL != materialURLString || (usingMaterialData && materialDataChanged)) { removeMaterial(); _materialURL = materialURLString; @@ -156,8 +165,8 @@ void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool u _currentMaterialName = split.last().toStdString(); } - if (usingUserData) { - _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8()), materialURLString); + if (usingMaterialData) { + _parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getMaterialData().toUtf8()), materialURLString); // Since our material changed, the current name might not be valid anymore, so we need to update setCurrentMaterialName(_currentMaterialName); @@ -191,11 +200,11 @@ void MaterialEntityItem::setCurrentMaterialName(const std::string& currentMateri } } -void MaterialEntityItem::setUserData(const QString& userData) { - if (_userData != userData) { - EntityItem::setUserData(userData); - if (_materialURL.startsWith("userData")) { - // Trigger material update when user data changes +void MaterialEntityItem::setMaterialData(const QString& materialData) { + if (_materialData != materialData) { + _materialData = materialData; + if (_materialURL.startsWith("materialData")) { + // Trigger material update when material data changes setMaterialURL(_materialURL, true); } } @@ -249,28 +258,12 @@ void MaterialEntityItem::setParentID(const QUuid& parentID) { } } -void MaterialEntityItem::setClientOnly(bool clientOnly) { - if (getClientOnly() != clientOnly) { - removeMaterial(); - EntityItem::setClientOnly(clientOnly); - applyMaterial(); - } -} - -void MaterialEntityItem::setOwningAvatarID(const QUuid& owningAvatarID) { - if (getOwningAvatarID() != owningAvatarID) { - removeMaterial(); - EntityItem::setOwningAvatarID(owningAvatarID); - applyMaterial(); - } -} - void MaterialEntityItem::removeMaterial() { graphics::MaterialPointer material = getMaterial(); if (!material) { return; } - QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID(); + QUuid parentID = getParentID(); if (parentID.isNull()) { return; } @@ -294,7 +287,7 @@ void MaterialEntityItem::removeMaterial() { void MaterialEntityItem::applyMaterial() { _retryApply = false; graphics::MaterialPointer material = getMaterial(); - QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID(); + QUuid parentID = getParentID(); if (!material || parentID.isNull()) { return; } @@ -328,11 +321,6 @@ void MaterialEntityItem::postParentFixup() { applyMaterial(); } -void MaterialEntityItem::preDelete() { - EntityItem::preDelete(); - removeMaterial(); -} - void MaterialEntityItem::update(const quint64& now) { if (_retryApply) { applyMaterial(); diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h index f77077a782..969eb577ff 100644 --- a/libraries/entities/src/MaterialEntityItem.h +++ b/libraries/entities/src/MaterialEntityItem.h @@ -21,6 +21,7 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); MaterialEntityItem(const EntityItemID& entityItemID); + ~MaterialEntityItem(); ALLOW_INSTANTIATION // This class can be instantiated @@ -53,7 +54,7 @@ public: virtual void setUnscaledDimensions(const glm::vec3& value) override; QString getMaterialURL() const { return _materialURL; } - void setMaterialURL(const QString& materialURLString, bool userDataChanged = false); + void setMaterialURL(const QString& materialURLString, bool materialDataChanged = false); void setCurrentMaterialName(const std::string& currentMaterialName); @@ -73,21 +74,20 @@ public: float getMaterialMappingRot() const { return _materialMappingRot; } void setMaterialMappingRot(const float& materialMappingRot); + QString getMaterialData() const { return _materialData; } + void setMaterialData(const QString& materialData); + std::shared_ptr getMaterial() const; - void setUserData(const QString& userData) override; void setParentID(const QUuid& parentID) override; - void setClientOnly(bool clientOnly) override; - void setOwningAvatarID(const QUuid& owningAvatarID) override; void applyMaterial(); void removeMaterial(); void postParentFixup() override; - void preDelete() override; private: - // URL for this material. Currently, only JSON format is supported. Set to "userData" to use the user data to live edit a material. + // URL for this material. Currently, only JSON format is supported. Set to "materialData" to use the material data to live edit a material. // The following fields are supported in the JSON: // materialVersion: a uint for the version of this network material (currently, only 1 is supported) // materials, which is either an object or an array of objects, each with the following properties: @@ -117,6 +117,7 @@ private: glm::vec2 _materialMappingScale { 1, 1 }; // How much to rotate this material within its parent's UV-space (degrees) float _materialMappingRot { 0 }; + QString _materialData; NetworkMaterialResourcePointer _networkMaterial; NetworkMaterialResource::ParsedMaterials _parsedMaterials; diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 60ba429938..99f18d2dac 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -117,8 +117,10 @@ ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem( EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class - properties.setColor(getXColor()); properties.setShape(entity::stringFromShape(getShape())); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); + return properties; } diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h index 97202afcf7..adc33b764b 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h @@ -105,7 +105,7 @@ public: protected: - float _alpha { 1 }; // FIXME: This property is not used. + float _alpha { 1.0f }; rgbColor _color; entity::Shape _shape { entity::Shape::Sphere }; diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index a2aba0169d..301011928b 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -9,8 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -//#include - #include "SimpleEntitySimulation.h" #include @@ -27,23 +25,25 @@ void SimpleEntitySimulation::clearOwnership(const QUuid& ownerID) { EntityItemPointer entity = *itemItr; if (entity->getSimulatorID() == ownerID) { // the simulator has abandonded this object --> remove from owned list - qCDebug(entities) << "auto-removing simulation owner " << entity->getSimulatorID(); itemItr = _entitiesWithSimulationOwner.erase(itemItr); if (entity->getDynamic() && entity->hasLocalVelocity()) { // it is still moving dynamically --> add to orphaned list _entitiesThatNeedSimulationOwner.insert(entity); uint64_t expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; - if (expiry < _nextOwnerlessExpiry) { - _nextOwnerlessExpiry = expiry; - } + _nextOwnerlessExpiry = glm::min(_nextOwnerlessExpiry, expiry); } // remove ownership and dirty all the tree elements that contain the it entity->clearSimulationOwnership(); entity->markAsChangedOnServer(); - DirtyOctreeElementOperator op(entity->getElement()); - getEntityTree()->recurseTreeWithOperator(&op); + if (auto element = entity->getElement()) { + auto tree = getEntityTree(); + tree->withReadLock([&] { + DirtyOctreeElementOperator op(element); + tree->recurseTreeWithOperator(&op); + }); + } } else { ++itemItr; } @@ -51,37 +51,8 @@ void SimpleEntitySimulation::clearOwnership(const QUuid& ownerID) { } void SimpleEntitySimulation::updateEntitiesInternal(uint64_t now) { - if (now > _nextOwnerlessExpiry) { - // search for ownerless objects that have expired - QMutexLocker lock(&_mutex); - _nextOwnerlessExpiry = std::numeric_limits::max(); - SetOfEntities::iterator itemItr = _entitiesThatNeedSimulationOwner.begin(); - while (itemItr != _entitiesThatNeedSimulationOwner.end()) { - EntityItemPointer entity = *itemItr; - uint64_t expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; - if (expiry < now) { - // no simulators have volunteered ownership --> remove from list - itemItr = _entitiesThatNeedSimulationOwner.erase(itemItr); - - if (entity->getSimulatorID().isNull() && entity->getDynamic() && entity->hasLocalVelocity()) { - // zero the derivatives - entity->setVelocity(Vectors::ZERO); - entity->setAngularVelocity(Vectors::ZERO); - entity->setAcceleration(Vectors::ZERO); - - // dirty all the tree elements that contain it - entity->markAsChangedOnServer(); - DirtyOctreeElementOperator op(entity->getElement()); - getEntityTree()->recurseTreeWithOperator(&op); - } - } else { - ++itemItr; - if (expiry < _nextOwnerlessExpiry) { - _nextOwnerlessExpiry = expiry; - } - } - } - } + expireStaleOwnerships(now); + stopOwnerlessEntities(now); } void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) { @@ -93,13 +64,12 @@ void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) { if (!entity->getSimulatorID().isNull()) { QMutexLocker lock(&_mutex); _entitiesWithSimulationOwner.insert(entity); + _nextStaleOwnershipExpiry = glm::min(_nextStaleOwnershipExpiry, entity->getSimulationOwnershipExpiry()); } else if (entity->getDynamic() && entity->hasLocalVelocity()) { QMutexLocker lock(&_mutex); _entitiesThatNeedSimulationOwner.insert(entity); uint64_t expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; - if (expiry < _nextOwnerlessExpiry) { - _nextOwnerlessExpiry = expiry; - } + _nextOwnerlessExpiry = glm::min(_nextOwnerlessExpiry, expiry); } } @@ -128,13 +98,12 @@ void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { if (entity->getDynamic() && entity->hasLocalVelocity()) { _entitiesThatNeedSimulationOwner.insert(entity); uint64_t expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; - if (expiry < _nextOwnerlessExpiry) { - _nextOwnerlessExpiry = expiry; - } + _nextOwnerlessExpiry = glm::min(_nextOwnerlessExpiry, expiry); } } else { QMutexLocker lock(&_mutex); _entitiesWithSimulationOwner.insert(entity); + _nextStaleOwnershipExpiry = glm::min(_nextStaleOwnershipExpiry, entity->getSimulationOwnershipExpiry()); _entitiesThatNeedSimulationOwner.remove(entity); } entity->clearDirtyFlags(); @@ -155,3 +124,58 @@ void SimpleEntitySimulation::sortEntitiesThatMoved() { } EntitySimulation::sortEntitiesThatMoved(); } + +void SimpleEntitySimulation::expireStaleOwnerships(uint64_t now) { + if (now > _nextStaleOwnershipExpiry) { + _nextStaleOwnershipExpiry = (uint64_t)(-1); + SetOfEntities::iterator itemItr = _entitiesWithSimulationOwner.begin(); + while (itemItr != _entitiesWithSimulationOwner.end()) { + EntityItemPointer entity = *itemItr; + uint64_t expiry = entity->getSimulationOwnershipExpiry(); + if (now > expiry) { + itemItr = _entitiesWithSimulationOwner.erase(itemItr); + + // remove ownership and dirty all the tree elements that contain the it + entity->clearSimulationOwnership(); + entity->markAsChangedOnServer(); + DirtyOctreeElementOperator op(entity->getElement()); + getEntityTree()->recurseTreeWithOperator(&op); + } else { + _nextStaleOwnershipExpiry = glm::min(_nextStaleOwnershipExpiry, expiry); + ++itemItr; + } + } + } +} + +void SimpleEntitySimulation::stopOwnerlessEntities(uint64_t now) { + if (now > _nextOwnerlessExpiry) { + // search for ownerless objects that have expired + QMutexLocker lock(&_mutex); + _nextOwnerlessExpiry = (uint64_t)(-1); + SetOfEntities::iterator itemItr = _entitiesThatNeedSimulationOwner.begin(); + while (itemItr != _entitiesThatNeedSimulationOwner.end()) { + EntityItemPointer entity = *itemItr; + uint64_t expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD; + if (expiry < now) { + // no simulators have volunteered ownership --> remove from list + itemItr = _entitiesThatNeedSimulationOwner.erase(itemItr); + + if (entity->getSimulatorID().isNull() && entity->getDynamic() && entity->hasLocalVelocity()) { + // zero the derivatives + entity->setVelocity(Vectors::ZERO); + entity->setAngularVelocity(Vectors::ZERO); + entity->setAcceleration(Vectors::ZERO); + + // dirty all the tree elements that contain it + entity->markAsChangedOnServer(); + DirtyOctreeElementOperator op(entity->getElement()); + getEntityTree()->recurseTreeWithOperator(&op); + } + } else { + _nextOwnerlessExpiry = glm::min(_nextOwnerlessExpiry, expiry); + ++itemItr; + } + } + } +} diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 95c996a920..8ac9b69e93 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -23,22 +23,26 @@ using SimpleEntitySimulationPointer = std::shared_ptr; class SimpleEntitySimulation : public EntitySimulation { public: SimpleEntitySimulation() : EntitySimulation() { } - virtual ~SimpleEntitySimulation() { clearEntitiesInternal(); } + ~SimpleEntitySimulation() { clearEntitiesInternal(); } void clearOwnership(const QUuid& ownerID); protected: - virtual void updateEntitiesInternal(uint64_t now) override; - virtual void addEntityInternal(EntityItemPointer entity) override; - virtual void removeEntityInternal(EntityItemPointer entity) override; - virtual void changeEntityInternal(EntityItemPointer entity) override; - virtual void clearEntitiesInternal() override; + void updateEntitiesInternal(uint64_t now) override; + void addEntityInternal(EntityItemPointer entity) override; + void removeEntityInternal(EntityItemPointer entity) override; + void changeEntityInternal(EntityItemPointer entity) override; + void clearEntitiesInternal() override; - virtual void sortEntitiesThatMoved() override; + void sortEntitiesThatMoved() override; + + void expireStaleOwnerships(uint64_t now); + void stopOwnerlessEntities(uint64_t now); SetOfEntities _entitiesWithSimulationOwner; SetOfEntities _entitiesThatNeedSimulationOwner; uint64_t _nextOwnerlessExpiry { 0 }; + uint64_t _nextStaleOwnershipExpiry { (uint64_t)(-1) }; }; #endif // hifi_SimpleEntitySimulation_h diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTexelFormat.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTexelFormat.cpp index 99a9afb4c4..4d94f8d8e7 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTexelFormat.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTexelFormat.cpp @@ -370,7 +370,36 @@ GLenum GLTexelFormat::evalGLTexelFormatInternal(const gpu::Element& dstFormat) { case gpu::COMPRESSED_BC7_SRGBA: result = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; break; - + case gpu::COMPRESSED_ETC2_RGB: + result = GL_COMPRESSED_RGB8_ETC2; + break; + case gpu::COMPRESSED_ETC2_SRGB: + result = GL_COMPRESSED_SRGB8_ETC2; + break; + case gpu::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA: + result = GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + break; + case gpu::COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA: + result = GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; + break; + case gpu::COMPRESSED_ETC2_RGBA: + result = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; + case gpu::COMPRESSED_ETC2_SRGBA: + result = GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; + break; + case gpu::COMPRESSED_EAC_RED: + result = GL_COMPRESSED_R11_EAC; + break; + case gpu::COMPRESSED_EAC_RED_SIGNED: + result = GL_COMPRESSED_SIGNED_R11_EAC; + break; + case gpu::COMPRESSED_EAC_XY: + result = GL_COMPRESSED_RG11_EAC; + break; + case gpu::COMPRESSED_EAC_XY_SIGNED: + result = GL_COMPRESSED_SIGNED_RG11_EAC; + break; default: qCWarning(gpugllogging) << "Unknown combination of texel format"; } @@ -531,6 +560,36 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E case gpu::COMPRESSED_BC7_SRGBA: texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; break; + case gpu::COMPRESSED_ETC2_RGB: + texel.internalFormat = GL_COMPRESSED_RGB8_ETC2; + break; + case gpu::COMPRESSED_ETC2_SRGB: + texel.internalFormat = GL_COMPRESSED_SRGB8_ETC2; + break; + case gpu::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA: + texel.internalFormat = GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + break; + case gpu::COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA: + texel.internalFormat = GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; + break; + case gpu::COMPRESSED_ETC2_RGBA: + texel.internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; + case gpu::COMPRESSED_ETC2_SRGBA: + texel.internalFormat = GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; + break; + case gpu::COMPRESSED_EAC_RED: + texel.internalFormat = GL_COMPRESSED_R11_EAC; + break; + case gpu::COMPRESSED_EAC_RED_SIGNED: + texel.internalFormat = GL_COMPRESSED_SIGNED_R11_EAC; + break; + case gpu::COMPRESSED_EAC_XY: + texel.internalFormat = GL_COMPRESSED_RG11_EAC; + break; + case gpu::COMPRESSED_EAC_XY_SIGNED: + texel.internalFormat = GL_COMPRESSED_SIGNED_RG11_EAC; + break; default: qCWarning(gpugllogging) << "Unknown combination of texel format"; } @@ -895,7 +954,36 @@ GLTexelFormat GLTexelFormat::evalGLTexelFormat(const Element& dstFormat, const E case gpu::COMPRESSED_BC7_SRGBA: texel.internalFormat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; break; - + case gpu::COMPRESSED_ETC2_RGB: + texel.internalFormat = GL_COMPRESSED_RGB8_ETC2; + break; + case gpu::COMPRESSED_ETC2_SRGB: + texel.internalFormat = GL_COMPRESSED_SRGB8_ETC2; + break; + case gpu::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA: + texel.internalFormat = GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + break; + case gpu::COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA: + texel.internalFormat = GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; + break; + case gpu::COMPRESSED_ETC2_RGBA: + texel.internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; + case gpu::COMPRESSED_ETC2_SRGBA: + texel.internalFormat = GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; + break; + case gpu::COMPRESSED_EAC_RED: + texel.internalFormat = GL_COMPRESSED_R11_EAC; + break; + case gpu::COMPRESSED_EAC_RED_SIGNED: + texel.internalFormat = GL_COMPRESSED_SIGNED_R11_EAC; + break; + case gpu::COMPRESSED_EAC_XY: + texel.internalFormat = GL_COMPRESSED_RG11_EAC; + break; + case gpu::COMPRESSED_EAC_XY_SIGNED: + texel.internalFormat = GL_COMPRESSED_SIGNED_RG11_EAC; + break; default: qCWarning(gpugllogging) << "Unknown combination of texel format"; } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 3c59781f78..9479321747 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -173,6 +173,8 @@ protected: void makeProgramBindings(ShaderObject& shaderObject) override; int makeResourceBufferSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,Shader::SlotSet& resourceBuffers) override; + static bool supportedTextureFormat(const gpu::Element& format); + }; } } diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp index 722ea63a77..0298b8b892 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendTexture.cpp @@ -19,6 +19,24 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl41; +bool GL41Backend::supportedTextureFormat(const gpu::Element& format) { + switch (format.getSemantic()) { + case gpu::Semantic::COMPRESSED_ETC2_RGB: + case gpu::Semantic::COMPRESSED_ETC2_SRGB: + case gpu::Semantic::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA: + case gpu::Semantic::COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA: + case gpu::Semantic::COMPRESSED_ETC2_RGBA: + case gpu::Semantic::COMPRESSED_ETC2_SRGBA: + case gpu::Semantic::COMPRESSED_EAC_RED: + case gpu::Semantic::COMPRESSED_EAC_RED_SIGNED: + case gpu::Semantic::COMPRESSED_EAC_XY: + case gpu::Semantic::COMPRESSED_EAC_XY_SIGNED: + return false; + default: + return true; + } +} + GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) { if (!texturePointer) { return nullptr; @@ -34,6 +52,11 @@ GLTexture* GL41Backend::syncGPUObject(const TexturePointer& texturePointer) { return nullptr; } + // Check whether the texture is in a format we can deal with + if (!supportedTextureFormat(texture.getTexelFormat())) { + return nullptr; + } + GL41Texture* object = Backend::getGPUObject(texture); if (!object) { switch (texture.getUsageType()) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 5a5d701150..4d5ffefa67 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -206,6 +206,16 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const case GL_COMPRESSED_RG_RGTC2: case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: + case GL_COMPRESSED_RGB8_ETC2: + case GL_COMPRESSED_SRGB8_ETC2: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_RGBA8_ETC2_EAC: + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + case GL_COMPRESSED_R11_EAC: + case GL_COMPRESSED_SIGNED_R11_EAC: + case GL_COMPRESSED_RG11_EAC: + case GL_COMPRESSED_SIGNED_RG11_EAC: glCompressedTextureSubImage2D(_id, mip, 0, yOffset, size.x, size.y, internalFormat, static_cast(sourceSize), sourcePointer); break; @@ -222,6 +232,16 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const case GL_COMPRESSED_RG_RGTC2: case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: + case GL_COMPRESSED_RGB8_ETC2: + case GL_COMPRESSED_SRGB8_ETC2: + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_RGBA8_ETC2_EAC: + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + case GL_COMPRESSED_R11_EAC: + case GL_COMPRESSED_SIGNED_R11_EAC: + case GL_COMPRESSED_RG11_EAC: + case GL_COMPRESSED_SIGNED_RG11_EAC: if (glCompressedTextureSubImage2DEXT) { auto target = GLTexture::CUBE_FACE_LAYOUT[face]; glCompressedTextureSubImage2DEXT(_id, target, mip, 0, yOffset, size.x, size.y, internalFormat, diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp index 6bc55a23d4..2009dc5dc9 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendTexture.cpp @@ -20,9 +20,21 @@ using namespace gpu::gl; using namespace gpu::gles; bool GLESBackend::supportedTextureFormat(const gpu::Element& format) { - // FIXME distinguish between GLES and GL compressed formats after support - // for the former is added to gpu::Element - return !format.isCompressed(); + switch (format.getSemantic()) { + case gpu::Semantic::COMPRESSED_ETC2_RGB: + case gpu::Semantic::COMPRESSED_ETC2_SRGB: + case gpu::Semantic::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA: + case gpu::Semantic::COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA: + case gpu::Semantic::COMPRESSED_ETC2_RGBA: + case gpu::Semantic::COMPRESSED_ETC2_SRGBA: + case gpu::Semantic::COMPRESSED_EAC_RED: + case gpu::Semantic::COMPRESSED_EAC_RED_SIGNED: + case gpu::Semantic::COMPRESSED_EAC_XY: + case gpu::Semantic::COMPRESSED_EAC_XY_SIGNED: + return true; + default: + return !format.isCompressed(); + } } GLTexture* GLESBackend::syncGPUObject(const TexturePointer& texturePointer) { @@ -231,6 +243,29 @@ GLESFixedAllocationTexture::GLESFixedAllocationTexture(const std::weak_ptrgetType() == VERTEX) { diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 6793948d13..4d82aba595 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -128,6 +128,7 @@ public: uint8 _wrapModeV = WRAP_REPEAT; uint8 _wrapModeW = WRAP_REPEAT; + uint8 _mipOffset = 0; uint8 _minMip = 0; uint8 _maxMip = MAX_MIP_LEVEL; @@ -142,6 +143,7 @@ public: _wrapModeU == other._wrapModeU && _wrapModeV == other._wrapModeV && _wrapModeW == other._wrapModeW && + _mipOffset == other._mipOffset && _minMip == other._minMip && _maxMip == other._maxMip; } @@ -164,6 +166,7 @@ public: ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); } bool doComparison() const { return getComparisonFunction() != ALWAYS; } + uint8 getMipOffset() const { return _desc._mipOffset; } uint8 getMinMip() const { return _desc._minMip; } uint8 getMaxMip() const { return _desc._maxMip; } diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp index 803acbd961..5e354c0a5c 100644 --- a/libraries/gpu/src/gpu/Texture_ktx.cpp +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -574,20 +574,40 @@ bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RED, ktx::GLInternalFormat::R8, ktx::GLBaseInternalFormat::RED); } else if (texelFormat == Format::VEC2NU8_XY && mipFormat == Format::VEC2NU8_XY) { header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RG, ktx::GLInternalFormat::RG8, ktx::GLBaseInternalFormat::RG); - } else if (texelFormat == Format::COLOR_COMPRESSED_SRGB && mipFormat == Format::COLOR_COMPRESSED_SRGB) { + } else if (texelFormat == Format::COLOR_COMPRESSED_BCX_SRGB && mipFormat == Format::COLOR_COMPRESSED_BCX_SRGB) { header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGB); - } else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_MASK && mipFormat == Format::COLOR_COMPRESSED_SRGBA_MASK) { + } else if (texelFormat == Format::COLOR_COMPRESSED_BCX_SRGBA_MASK && mipFormat == Format::COLOR_COMPRESSED_BCX_SRGBA_MASK) { header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGBA); - } else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA && mipFormat == Format::COLOR_COMPRESSED_SRGBA) { + } else if (texelFormat == Format::COLOR_COMPRESSED_BCX_SRGBA && mipFormat == Format::COLOR_COMPRESSED_BCX_SRGBA) { header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, ktx::GLBaseInternalFormat::RGBA); - } else if (texelFormat == Format::COLOR_COMPRESSED_RED && mipFormat == Format::COLOR_COMPRESSED_RED) { + } else if (texelFormat == Format::COLOR_COMPRESSED_BCX_RED && mipFormat == Format::COLOR_COMPRESSED_BCX_RED) { header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RED_RGTC1, ktx::GLBaseInternalFormat::RED); - } else if (texelFormat == Format::COLOR_COMPRESSED_XY && mipFormat == Format::COLOR_COMPRESSED_XY) { + } else if (texelFormat == Format::COLOR_COMPRESSED_BCX_XY && mipFormat == Format::COLOR_COMPRESSED_BCX_XY) { header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RG_RGTC2, ktx::GLBaseInternalFormat::RG); - } else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH && mipFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH) { + } else if (texelFormat == Format::COLOR_COMPRESSED_BCX_SRGBA_HIGH && mipFormat == Format::COLOR_COMPRESSED_BCX_SRGBA_HIGH) { header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, ktx::GLBaseInternalFormat::RGBA); - } else if (texelFormat == Format::COLOR_COMPRESSED_HDR_RGB && mipFormat == Format::COLOR_COMPRESSED_HDR_RGB) { + } else if (texelFormat == Format::COLOR_COMPRESSED_BCX_HDR_RGB && mipFormat == Format::COLOR_COMPRESSED_BCX_HDR_RGB) { header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, ktx::GLBaseInternalFormat::RGB); + } else if (texelFormat == Format::COLOR_COMPRESSED_ETC2_RGB && mipFormat == Format::COLOR_COMPRESSED_ETC2_RGB) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RGB8_ETC2, ktx::GLBaseInternalFormat::RGB); + } else if (texelFormat == Format::COLOR_COMPRESSED_ETC2_SRGB && mipFormat == Format::COLOR_COMPRESSED_ETC2_SRGB) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB8_ETC2, ktx::GLBaseInternalFormat::RGB); + } else if (texelFormat == Format::COLOR_COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA && mipFormat == Format::COLOR_COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, ktx::GLBaseInternalFormat::RGBA); + } else if (texelFormat == Format::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA && mipFormat == Format::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, ktx::GLBaseInternalFormat::RGBA); + } else if (texelFormat == Format::COLOR_COMPRESSED_ETC2_RGBA && mipFormat == Format::COLOR_COMPRESSED_ETC2_RGBA) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RGBA8_ETC2_EAC, ktx::GLBaseInternalFormat::RGBA); + } else if (texelFormat == Format::COLOR_COMPRESSED_ETC2_SRGBA && mipFormat == Format::COLOR_COMPRESSED_ETC2_SRGBA) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, ktx::GLBaseInternalFormat::RGBA); + } else if (texelFormat == Format::COLOR_COMPRESSED_EAC_RED && mipFormat == Format::COLOR_COMPRESSED_EAC_RED) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_R11_EAC, ktx::GLBaseInternalFormat::RED); + } else if (texelFormat == Format::COLOR_COMPRESSED_EAC_RED_SIGNED && mipFormat == Format::COLOR_COMPRESSED_EAC_RED_SIGNED) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SIGNED_R11_EAC, ktx::GLBaseInternalFormat::RED); + } else if (texelFormat == Format::COLOR_COMPRESSED_EAC_XY && mipFormat == Format::COLOR_COMPRESSED_EAC_XY) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RG11_EAC, ktx::GLBaseInternalFormat::RG); + } else if (texelFormat == Format::COLOR_COMPRESSED_EAC_XY_SIGNED && mipFormat == Format::COLOR_COMPRESSED_EAC_XY_SIGNED) { + header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SIGNED_RG11_EAC, ktx::GLBaseInternalFormat::RG); } else if (texelFormat == Format::COLOR_RGB9E5 && mipFormat == Format::COLOR_RGB9E5) { header.setUncompressed(ktx::GLType::UNSIGNED_INT_5_9_9_9_REV, 1, ktx::GLFormat::RGB, ktx::GLInternalFormat::RGB9_E5, ktx::GLBaseInternalFormat::RGB); } else if (texelFormat == Format::COLOR_R11G11B10 && mipFormat == Format::COLOR_R11G11B10) { @@ -642,31 +662,45 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E texelFormat = Format::COLOR_RGB9E5; } else if (header.isCompressed()) { if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) { - mipFormat = Format::COLOR_COMPRESSED_SRGB; - texelFormat = Format::COLOR_COMPRESSED_SRGB; + texelFormat = Format::COLOR_COMPRESSED_BCX_SRGB; } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) { - mipFormat = Format::COLOR_COMPRESSED_SRGBA_MASK; - texelFormat = Format::COLOR_COMPRESSED_SRGBA_MASK; + texelFormat = Format::COLOR_COMPRESSED_BCX_SRGBA_MASK; } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) { - mipFormat = Format::COLOR_COMPRESSED_SRGBA; - texelFormat = Format::COLOR_COMPRESSED_SRGBA; + texelFormat = Format::COLOR_COMPRESSED_BCX_SRGBA; } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RED_RGTC1) { - mipFormat = Format::COLOR_COMPRESSED_RED; - texelFormat = Format::COLOR_COMPRESSED_RED; + texelFormat = Format::COLOR_COMPRESSED_BCX_RED; } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RG_RGTC2) { - mipFormat = Format::COLOR_COMPRESSED_XY; - texelFormat = Format::COLOR_COMPRESSED_XY; + texelFormat = Format::COLOR_COMPRESSED_BCX_XY; } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) { - mipFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH; - texelFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH; + texelFormat = Format::COLOR_COMPRESSED_BCX_SRGBA_HIGH; } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) { - mipFormat = Format::COLOR_COMPRESSED_HDR_RGB; - texelFormat = Format::COLOR_COMPRESSED_HDR_RGB; + texelFormat = Format::COLOR_COMPRESSED_BCX_HDR_RGB; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGB8_ETC2) { + texelFormat = Format::COLOR_COMPRESSED_ETC2_RGB; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB8_ETC2) { + texelFormat = Format::COLOR_COMPRESSED_ETC2_SRGB; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) { + texelFormat = Format::COLOR_COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) { + texelFormat = Format::COLOR_COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RGBA8_ETC2_EAC) { + texelFormat = Format::COLOR_COMPRESSED_ETC2_RGBA; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) { + texelFormat = Format::COLOR_COMPRESSED_ETC2_SRGBA; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_R11_EAC) { + texelFormat = Format::COLOR_COMPRESSED_EAC_RED; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SIGNED_R11_EAC) { + texelFormat = Format::COLOR_COMPRESSED_EAC_RED_SIGNED; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RG11_EAC) { + texelFormat = Format::COLOR_COMPRESSED_EAC_XY; + } else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SIGNED_RG11_EAC) { + texelFormat = Format::COLOR_COMPRESSED_EAC_XY_SIGNED; } else { return false; } + mipFormat = texelFormat; } else { return false; } return true; -} +} \ No newline at end of file diff --git a/libraries/graphics/src/graphics/GpuHelpers.cpp b/libraries/graphics/src/graphics/GpuHelpers.cpp index 0c3bd945e1..b864b0f040 100644 --- a/libraries/graphics/src/graphics/GpuHelpers.cpp +++ b/libraries/graphics/src/graphics/GpuHelpers.cpp @@ -87,6 +87,17 @@ namespace gpu { { Semantic::COMPRESSED_BC6_RGB, "compressed_bc6_rgb" }, { Semantic::COMPRESSED_BC7_SRGBA, "compressed_bc7_srgba" }, + { Semantic::COMPRESSED_ETC2_RGB, "compressed_etc2_rgb" }, + { Semantic::COMPRESSED_ETC2_SRGB, "compressed_etc2_srgb" }, + { Semantic::COMPRESSED_ETC2_RGB_PUNCHTHROUGH_ALPHA, "compressed_etc2_rgb_punchthrough_alpha" }, + { Semantic::COMPRESSED_ETC2_SRGB_PUNCHTHROUGH_ALPHA, "compressed_etc2_srgb_punchthrough_alpha" }, + { Semantic::COMPRESSED_ETC2_RGBA, "compressed_etc2_rgba" }, + { Semantic::COMPRESSED_ETC2_SRGBA, "compressed_etc2_srgba" }, + { Semantic::COMPRESSED_EAC_RED, "compressed_eac_red" }, + { Semantic::COMPRESSED_EAC_RED_SIGNED, "compressed_eac_red_signed" }, + { Semantic::COMPRESSED_EAC_XY, "compressed_eac_xy" }, + { Semantic::COMPRESSED_EAC_XY_SIGNED, "compressed_eac_xy_signed" }, + { Semantic::_LAST_COMPRESSED, "_last_compressed" }, { Semantic::R11G11B10, "r11g11b10" }, diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 696e311495..c1c07838c7 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -466,7 +466,8 @@ void generateHDRMips(gpu::Texture* texture, QImage&& image, const std::atomicgetStoredMipFormat(); - if (mipFormat == gpu::Element::COLOR_COMPRESSED_SRGB) { + if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGB) { compressionOptions.setFormat(nvtt::Format_BC1); - } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_SRGBA_MASK) { + } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_MASK) { alphaMode = nvtt::AlphaMode_Transparency; compressionOptions.setFormat(nvtt::Format_BC1a); - } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_SRGBA) { + } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA) { alphaMode = nvtt::AlphaMode_Transparency; compressionOptions.setFormat(nvtt::Format_BC3); - } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_RED) { + } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_RED) { compressionOptions.setFormat(nvtt::Format_BC4); - } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_XY) { + } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_XY) { compressionOptions.setFormat(nvtt::Format_BC5); - } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_SRGBA_HIGH) { + } else if (mipFormat == gpu::Element::COLOR_COMPRESSED_BCX_SRGBA_HIGH) { alphaMode = nvtt::AlphaMode_Transparency; compressionOptions.setFormat(nvtt::Format_BC7); } else if (mipFormat == gpu::Element::COLOR_RGBA_32) { @@ -736,13 +738,21 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(QImage&& srcIma gpu::Element formatMip; gpu::Element formatGPU; if (isColorTexturesCompressionEnabled()) { +#ifndef USE_GLES if (validAlpha) { // NOTE: This disables BC1a compression because it was producing odd artifacts on text textures // for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts). - formatGPU = gpu::Element::COLOR_COMPRESSED_SRGBA; + formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_SRGBA; } else { - formatGPU = gpu::Element::COLOR_COMPRESSED_SRGB; + formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_SRGB; } +#else + if (validAlpha) { + formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGBA; + } else { + formatGPU = gpu::Element::COLOR_COMPRESSED_ETC2_SRGB; + } +#endif formatMip = formatGPU; } else { #ifdef USE_GLES @@ -869,8 +879,12 @@ gpu::TexturePointer TextureUsage::process2DTextureNormalMapFromImage(QImage&& sr gpu::Element formatMip = gpu::Element::VEC2NU8_XY; gpu::Element formatGPU = gpu::Element::VEC2NU8_XY; if (isNormalTexturesCompressionEnabled()) { - formatMip = gpu::Element::COLOR_COMPRESSED_XY; - formatGPU = gpu::Element::COLOR_COMPRESSED_XY; +#ifndef USE_GLES + formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_XY; +#else + formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_XY; +#endif + formatMip = formatGPU; } theTexture = gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Texture::MAX_NUM_MIPS, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)); @@ -903,8 +917,12 @@ gpu::TexturePointer TextureUsage::process2DTextureGrayscaleFromImage(QImage&& sr gpu::Element formatMip; gpu::Element formatGPU; if (isGrayscaleTexturesCompressionEnabled()) { - formatMip = gpu::Element::COLOR_COMPRESSED_RED; - formatGPU = gpu::Element::COLOR_COMPRESSED_RED; +#ifndef USE_GLES + formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_RED; +#else + formatGPU = gpu::Element::COLOR_COMPRESSED_EAC_RED; +#endif + formatMip = formatGPU; } else { formatMip = gpu::Element::COLOR_R_8; formatGPU = gpu::Element::COLOR_R_8; @@ -1271,8 +1289,9 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(QImage&& srcI gpu::Element formatMip; gpu::Element formatGPU; if (isCubeTexturesCompressionEnabled()) { - formatMip = gpu::Element::COLOR_COMPRESSED_HDR_RGB; - formatGPU = gpu::Element::COLOR_COMPRESSED_HDR_RGB; + // TODO: gles: pick HDR ETC format + formatMip = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; + formatGPU = gpu::Element::COLOR_COMPRESSED_BCX_HDR_RGB; } else { formatMip = HDR_FORMAT; formatGPU = HDR_FORMAT; diff --git a/libraries/ktx/src/khronos/KHR.h b/libraries/ktx/src/khronos/KHR.h index cda22513ee..4ee893e4fc 100644 --- a/libraries/ktx/src/khronos/KHR.h +++ b/libraries/ktx/src/khronos/KHR.h @@ -358,6 +358,17 @@ namespace khronos { case InternalFormat::COMPRESSED_RG_RGTC2: // BC5 case InternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: // BC6 case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7 + // ETC2 / EAC + case InternalFormat::COMPRESSED_RGB8_ETC2: + case InternalFormat::COMPRESSED_SRGB8_ETC2: + case InternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case InternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case InternalFormat::COMPRESSED_RGBA8_ETC2_EAC: + case InternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + case InternalFormat::COMPRESSED_R11_EAC: + case InternalFormat::COMPRESSED_SIGNED_R11_EAC: + case InternalFormat::COMPRESSED_RG11_EAC: + case InternalFormat::COMPRESSED_SIGNED_RG11_EAC: return evalAlignedCompressedBlockCount<4>(value); default: @@ -370,12 +381,22 @@ namespace khronos { case InternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT: case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: case InternalFormat::COMPRESSED_RED_RGTC1: + case InternalFormat::COMPRESSED_RGB8_ETC2: + case InternalFormat::COMPRESSED_SRGB8_ETC2: + case InternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case InternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case InternalFormat::COMPRESSED_R11_EAC: + case InternalFormat::COMPRESSED_SIGNED_R11_EAC: return 8; case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: case InternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: case InternalFormat::COMPRESSED_RG_RGTC2: + case InternalFormat::COMPRESSED_RGBA8_ETC2_EAC: + case InternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + case InternalFormat::COMPRESSED_RG11_EAC: + case InternalFormat::COMPRESSED_SIGNED_RG11_EAC: return 16; default: diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 1954f40b44..04696cea1a 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -642,8 +642,12 @@ void NetworkTexture::ktxInitialDataRequestFinished() { } if (result == ResourceRequest::Success) { + +// This is an expensive operation that we do not want in release. +#ifdef DEBUG auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); +#endif _ktxHeaderData = _ktxHeaderRequest->getData(); _ktxHighMipData = _ktxMipRequest->getData(); diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 63ec841ffb..3d6bcd2e88 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -39,6 +39,10 @@ bool AddressManager::isConnected() { return DependencyManager::get()->getDomainHandler().isConnected(); } +QString AddressManager::getProtocol() const { + return _domainURL.scheme(); +} + QUrl AddressManager::currentAddress(bool domainOnly) const { QUrl hifiURL = _domainURL; diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index b42aec2771..b6a18b117d 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -145,7 +145,7 @@ public: }; bool isConnected(); - const QString& getProtocol() { return URL_SCHEME_HIFI; }; + QString getProtocol() const; QUrl currentAddress(bool domainOnly = false) const; QUrl currentFacingAddress() const; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index a83924ee58..b49b954b99 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::ShadowControl); + return static_cast(EntityVersion::MaterialData); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::RemovedJurisdictions); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 09fd31a41e..e0d3bcdb97 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -231,7 +231,8 @@ enum class EntityVersion : PacketVersion { ZoneStageRemoved, SoftEntities, MaterialEntities, - ShadowControl + ShadowControl, + MaterialData }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/octree/src/DirtyOctreeElementOperator.cpp b/libraries/octree/src/DirtyOctreeElementOperator.cpp index ed8d26cf72..ae01a3d608 100644 --- a/libraries/octree/src/DirtyOctreeElementOperator.cpp +++ b/libraries/octree/src/DirtyOctreeElementOperator.cpp @@ -14,6 +14,7 @@ DirtyOctreeElementOperator::DirtyOctreeElementOperator(const OctreeElementPointer& element) : _element(element) { assert(_element.get()); + _element->bumpChangedContent(); _point = _element->getAACube().calcCenter(); } diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 9ab5d9429d..514039713b 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -219,6 +219,9 @@ public: int getMyChildContaining(const AABox& box) const; int getMyChildContainingPoint(const glm::vec3& point) const; + void bumpChangedContent() { _lastChangedContent = usecTimestampNow(); } + uint64_t getLastChangedContent() const { return _lastChangedContent; } + protected: void deleteAllChildren(); @@ -235,6 +238,7 @@ protected: } _octalCode; quint64 _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes + uint64_t _lastChangedContent { 0 }; /// Client and server, pointers to child nodes, various encodings #ifdef SIMPLE_CHILD_ARRAY diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 6a25700ce8..c2bacd4949 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -365,6 +365,11 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) { return true; } + if (usecTimestampNow() > _entity->getSimulationOwnershipExpiry()) { + // send update every so often else server will revoke our ownership + return true; + } + _lastStep = simulationStep; if (glm::length2(_serverVelocity) > 0.0f) { // the entity-server doesn't know where avatars are, so it doesn't do simple extrapolation for children of @@ -525,8 +530,6 @@ void EntityMotionState::sendBid(OctreeEditPacketSender* packetSender, uint32_t s properties.setSimulationOwner(Physics::getSessionUUID(), bidPriority); // copy _bidPriority into pendingPriority... _entity->setPendingOwnershipPriority(_bidPriority, now); - // don't forget to remember that we have made a bid - _entity->rememberHasSimulationOwnershipBid(); EntityTreeElementPointer element = _entity->getElement(); EntityTreePointer tree = element ? element->getTree() : nullptr; @@ -585,6 +588,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ // set the LastEdited of the properties but NOT the entity itself quint64 now = usecTimestampNow(); properties.setLastEdited(now); + _entity->setSimulationOwnershipExpiry(now + MAX_OUTGOING_SIMULATION_UPDATE_PERIOD); if (_numInactiveUpdates > 0) { // the entity is stopped and inactive so we tell the server we're clearing simulatorID diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index d799577fc2..06e7069f72 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -158,7 +158,6 @@ void PhysicalEntitySimulation::clearEntitiesInternal() { EntityMotionState* motionState = static_cast(&(*stateItr)); assert(motionState); EntityItemPointer entity = motionState->getEntity(); - entity->setPhysicsInfo(nullptr); // TODO: someday when we invert the entities/physics lib dependencies we can let EntityItem delete its own PhysicsInfo // until then we must do it here delete motionState; diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index 9c1bb79355..2da1c41340 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -27,6 +27,8 @@ #include "impl/SharedObject.h" #include "impl/TextureCache.h" +#include "Profile.h" + using namespace hifi::qml; using namespace hifi::qml::impl; @@ -284,6 +286,7 @@ void OffscreenSurface::loadInternal(const QUrl& qmlSource, bool createNewContext, QQuickItem* parent, const QmlContextObjectCallback& callback) { + PROFILE_RANGE_EX(app, "OffscreenSurface::loadInternal", 0xffff00ff, 0, { std::make_pair("url", qmlSource.toDisplayString()) }); if (QThread::currentThread() != thread()) { qFatal("Called load on a non-surface thread"); } @@ -304,7 +307,11 @@ void OffscreenSurface::loadInternal(const QUrl& qmlSource, } auto targetContext = contextForUrl(finalQmlSource, parent, createNewContext); - auto qmlComponent = new QQmlComponent(getSurfaceContext()->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); + QQmlComponent* qmlComponent; + { + PROFILE_RANGE(app, "new QQmlComponent"); + qmlComponent = new QQmlComponent(getSurfaceContext()->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); + } if (qmlComponent->isLoading()) { connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) { finishQmlLoad(qmlComponent, targetContext, parent, callback); }); @@ -318,6 +325,7 @@ void OffscreenSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, QQuickItem* parent, const QmlContextObjectCallback& callback) { + PROFILE_RANGE(app, "finishQmlLoad"); disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { diff --git a/libraries/qml/src/qml/impl/SharedObject.cpp b/libraries/qml/src/qml/impl/SharedObject.cpp index d593169d94..b2057117f6 100644 --- a/libraries/qml/src/qml/impl/SharedObject.cpp +++ b/libraries/qml/src/qml/impl/SharedObject.cpp @@ -105,7 +105,10 @@ void SharedObject::create(OffscreenSurface* surface) { // Create a QML engine. auto qmlEngine = acquireEngine(surface); - _qmlContext = new QQmlContext(qmlEngine->rootContext(), qmlEngine); + { + PROFILE_RANGE(startup, "new QQmlContext"); + _qmlContext = new QQmlContext(qmlEngine->rootContext(), qmlEngine); + } surface->onRootContextCreated(_qmlContext); emit surface->rootContextCreated(_qmlContext); @@ -175,6 +178,7 @@ static size_t globalEngineRefCount{ 0 }; #endif QQmlEngine* SharedObject::acquireEngine(OffscreenSurface* surface) { + PROFILE_RANGE(startup, "acquireEngine"); Q_ASSERT(QThread::currentThread() == qApp->thread()); QQmlEngine* result = nullptr; diff --git a/libraries/render-utils/src/DeferredBufferRead.slh b/libraries/render-utils/src/DeferredBufferRead.slh index 3cbed3fcef..f7ab0957cc 100644 --- a/libraries/render-utils/src/DeferredBufferRead.slh +++ b/libraries/render-utils/src/DeferredBufferRead.slh @@ -118,7 +118,7 @@ DeferredFragment unpackDeferredFragmentNoPositionNoAmbient(vec2 texcoord) { <@include DeferredTransform.slh@> <$declareDeferredFrameTransform()$> -vec4 unpackDeferredPosition(DeferredFrameTransform deferredTransform, float depthValue, vec2 texcoord) { +vec4 unpackDeferredPosition(float depthValue, vec2 texcoord) { int side = 0; if (isStereo()) { if (texcoord.x > 0.5) { @@ -127,9 +127,14 @@ vec4 unpackDeferredPosition(DeferredFrameTransform deferredTransform, float dept } texcoord.x *= 2.0; } - float Zeye = evalZeyeFromZdb(depthValue); - return vec4(evalEyePositionFromZeye(side, Zeye, texcoord), 1.0); + return vec4(evalEyePositionFromZdb(side, depthValue, texcoord), 1.0); +} + +// This method to unpack position is fastesst +vec4 unpackDeferredPositionFromZdb(vec2 texcoord) { + float Zdb = texture(depthMap, texcoord).x; + return unpackDeferredPosition(Zdb, texcoord); } vec4 unpackDeferredPositionFromZeye(vec2 texcoord) { @@ -152,7 +157,7 @@ DeferredFragment unpackDeferredFragment(DeferredFrameTransform deferredTransform DeferredFragment frag = unpackDeferredFragmentNoPosition(texcoord); frag.depthVal = depthValue; - frag.position = unpackDeferredPosition(deferredTransform, frag.depthVal, texcoord); + frag.position = unpackDeferredPosition(frag.depthVal, texcoord); return frag; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index fc35267ddc..956b6c4a58 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -532,7 +532,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext, } } - auto& program = deferredLightingEffect->_directionalSkyboxLight; + auto program = deferredLightingEffect->_directionalSkyboxLight; LightLocationsPtr locations = deferredLightingEffect->_directionalSkyboxLightLocations; auto keyLight = lightAndShadow.first; diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index 5fccbd6a99..6b0e1cd642 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -122,17 +122,12 @@ float evalZeyeFromZdb(float depth) { return frameTransform._depthInfo.x / (depth * frameTransform._depthInfo.y + frameTransform._depthInfo.z); } -vec3 evalEyeNormal(vec3 C) { - //return normalize(cross(dFdy(C), dFdx(C))); - return normalize(cross(dFdx(C), dFdy(C))); +float evalZdbFromZeye(float Zeye) { + return (frameTransform._depthInfo.x - Zeye * frameTransform._depthInfo.z) / (Zeye * frameTransform._depthInfo.y); } -vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { - // compute the view space position using the depth - // basically manually pick the proj matrix components to do the inverse - float Xe = (-Zeye * (texcoord.x * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][0] - frameTransform._projection[side][3][0]) / frameTransform._projection[side][0][0]; - float Ye = (-Zeye * (texcoord.y * 2.0 - 1.0) - Zeye * frameTransform._projection[side][2][1] - frameTransform._projection[side][3][1]) / frameTransform._projection[side][1][1]; - return vec3(Xe, Ye, Zeye); +vec3 evalEyeNormal(vec3 C) { + return normalize(cross(dFdx(C), dFdy(C))); } vec3 evalEyePositionFromZdb(int side, float Zdb, vec2 texcoord) { @@ -143,6 +138,11 @@ vec3 evalEyePositionFromZdb(int side, float Zdb, vec2 texcoord) { return eyePos.xyz / eyePos.w; } +vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { + float Zdb = evalZdbFromZeye(Zeye); + return evalEyePositionFromZdb(side, Zdb, texcoord); +} + ivec2 getPixelPosTexcoordPosAndSide(in vec2 glFragCoord, out ivec2 pixelPos, out vec2 texcoordPos, out ivec4 stereoSide) { ivec2 fragPos = ivec2(glFragCoord.xy); diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slf b/libraries/render-utils/src/lightClusters_drawClusterContent.slf index 739709418d..d4d97c5b16 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slf @@ -32,7 +32,7 @@ void main(void) { // Grab the fragment data from the uv vec2 texCoord = varTexCoord0.st; - vec4 fragEyePos = unpackDeferredPositionFromZeye(texCoord); + vec4 fragEyePos = unpackDeferredPositionFromZdb(texCoord); vec4 fragWorldPos = getViewInverse() * fragEyePos; // From frag world pos find the cluster diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index ee2e6e0ccc..c51d45ed44 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -29,7 +29,7 @@ void main(void) { // Grab the fragment data from the uv vec2 texCoord = varTexCoord0.st; - vec4 fragEyePos = unpackDeferredPositionFromZeye(texCoord); + vec4 fragEyePos = unpackDeferredPositionFromZdb(texCoord); vec4 fragWorldPos = getViewInverse() * fragEyePos; // From frag world pos find the cluster diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 463b45451b..b0842d63cd 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -36,7 +36,7 @@ public: } }; -Engine::Engine() : Task("Engine", EngineTask::JobModel::create()), +Engine::Engine() : Task(EngineTask::JobModel::create("Engine")), _renderContext(std::make_shared()) { } diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 92e22d86f6..35cc66315b 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -134,9 +134,12 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p locations->lightClusterFrustumBufferUnit = -1; } - auto gpuPipeline = gpu::Pipeline::create(program, state); - auto shapePipeline = std::make_shared(gpuPipeline, locations, batchSetter, itemSetter); - addPipelineHelper(filter, key, 0, shapePipeline); + { + PROFILE_RANGE(app, "Pipeline::create"); + auto gpuPipeline = gpu::Pipeline::create(program, state); + auto shapePipeline = std::make_shared(gpuPipeline, locations, batchSetter, itemSetter); + addPipelineHelper(filter, key, 0, shapePipeline); + } } const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Key& key) const { diff --git a/libraries/shared/src/Profile.cpp b/libraries/shared/src/Profile.cpp index 97def2015a..f3cbbf9262 100644 --- a/libraries/shared/src/Profile.cpp +++ b/libraries/shared/src/Profile.cpp @@ -27,6 +27,7 @@ Q_LOGGING_CATEGORY(trace_simulation_animation, "trace.simulation.animation") Q_LOGGING_CATEGORY(trace_simulation_animation_detail, "trace.simulation.animation.detail") Q_LOGGING_CATEGORY(trace_simulation_physics, "trace.simulation.physics") Q_LOGGING_CATEGORY(trace_simulation_physics_detail, "trace.simulation.physics.detail") +Q_LOGGING_CATEGORY(trace_startup, "trace.startup") Q_LOGGING_CATEGORY(trace_workload, "trace.workload") #if defined(NSIGHT_FOUND) diff --git a/libraries/shared/src/Profile.h b/libraries/shared/src/Profile.h index f2a747afa3..e78ce210c9 100644 --- a/libraries/shared/src/Profile.h +++ b/libraries/shared/src/Profile.h @@ -32,6 +32,7 @@ Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_animation_detail) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics) Q_DECLARE_LOGGING_CATEGORY(trace_simulation_physics_detail) +Q_DECLARE_LOGGING_CATEGORY(trace_startup) Q_DECLARE_LOGGING_CATEGORY(trace_workload) class Duration { diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index 08df55dddd..022dd99200 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -47,7 +47,7 @@ protected: bool _doAbortTask{ false }; }; -// JobContext class is the base calss for the context object which is passed through all the Job::run calls thoughout the graph of jobs +// JobContext class is the base class for the context object which is passed through all the Job::run calls thoughout the graph of jobs // It is used to communicate to the job::run its context and various state information the job relies on. // It specifically provide access to: // - The taskFlow object allowing for messaging control flow commands from within a Job::run @@ -73,19 +73,21 @@ class JobConcept { public: using Config = JobConfig; - JobConcept(QConfigPointer config) : _config(config) {} + JobConcept(const std::string& name, QConfigPointer config) : _config(config), _name(name) {} virtual ~JobConcept() = default; + + const std::string& getName() const { return _name; } virtual const Varying getInput() const { return Varying(); } virtual const Varying getOutput() const { return Varying(); } virtual QConfigPointer& getConfiguration() { return _config; } virtual void applyConfiguration() = 0; - void setCPURunTime(double mstime) { std::static_pointer_cast(_config)->setCPURunTime(mstime); } QConfigPointer _config; protected: + const std::string _name; }; @@ -122,7 +124,7 @@ public: class Concept : public JobConcept { public: - Concept(QConfigPointer config) : JobConcept(config) {} + Concept(const std::string& name, QConfigPointer config) : JobConcept(name, config) {} virtual ~Concept() = default; virtual void run(const ContextPointer& jobContext) = 0; @@ -143,8 +145,8 @@ public: const Varying getOutput() const override { return _output; } template - Model(const Varying& input, QConfigPointer config, A&&... args) : - Concept(config), + Model(const std::string& name, const Varying& input, QConfigPointer config, A&&... args) : + Concept(name, config), _data(Data(std::forward(args)...)), _input(input), _output(Output()) { @@ -152,12 +154,14 @@ public: } template - static std::shared_ptr create(const Varying& input, A&&... args) { - return std::make_shared(input, std::make_shared(), std::forward(args)...); + static std::shared_ptr create(const std::string& name, const Varying& input, A&&... args) { + return std::make_shared(name, input, std::make_shared(), std::forward(args)...); } void applyConfiguration() override { + Duration profileRange(trace_render(), ("configure::" + JobConcept::getName()).c_str()); + jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); } @@ -173,8 +177,9 @@ public: template using ModelO = Model; template using ModelIO = Model; - Job(std::string name, ConceptPointer concept) : _concept(concept), _name(name) {} + Job(ConceptPointer concept) : _concept(concept) {} + const std::string& getName() const { return _concept->getName(); } const Varying getInput() const { return _concept->getInput(); } const Varying getOutput() const { return _concept->getOutput(); } QConfigPointer& getConfiguration() const { return _concept->getConfiguration(); } @@ -193,9 +198,9 @@ public: } virtual void run(const ContextPointer& jobContext) { - PerformanceTimer perfTimer(_name.c_str()); + PerformanceTimer perfTimer(getName().c_str()); // NOTE: rather than use the PROFILE_RANGE macro, we create a Duration manually - Duration profileRange(jobContext->profileCategory, _name.c_str()); + Duration profileRange(jobContext->profileCategory, ("run::" + getName()).c_str()); auto start = usecTimestampNow(); _concept->run(jobContext); @@ -203,11 +208,8 @@ public: _concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0); } - const std::string& getName() const { return _name; } - protected: ConceptPointer _concept; - std::string _name = ""; }; @@ -230,7 +232,7 @@ public: using ConceptPointer = typename JobType::ConceptPointer; using Jobs = std::vector; - Task(std::string name, ConceptPointer concept) : JobType(name, concept) {} + Task(ConceptPointer concept) : JobType(concept) {} class TaskConcept : public Concept { public: @@ -259,11 +261,11 @@ public: return jobIt; } - TaskConcept(const Varying& input, QConfigPointer config) : Concept(config), _input(input) {} + TaskConcept(const std::string& name, const Varying& input, QConfigPointer config) : Concept(name, config), _input(input) {} // Create a new job in the container's queue; returns the job's output template const Varying addJob(std::string name, const Varying& input, NA&&... args) { - _jobs.emplace_back(name, (NT::JobModel::create(input, std::forward(args)...))); + _jobs.emplace_back((NT::JobModel::create(name, input, std::forward(args)...))); // Conect the child config to this task's config std::static_pointer_cast(Concept::getConfiguration())->connectChildConfig(_jobs.back().getConfiguration(), name); @@ -284,16 +286,18 @@ public: Data _data; - TaskModel(const Varying& input, QConfigPointer config) : - TaskConcept(input, config), + TaskModel(const std::string& name, const Varying& input, QConfigPointer config) : + TaskConcept(name, input, config), _data(Data()) {} template - static std::shared_ptr create(const Varying& input, A&&... args) { - auto model = std::make_shared(input, std::make_shared()); - - model->_data.build(*(model), model->_input, model->_output, std::forward(args)...); + static std::shared_ptr create(const std::string& name, const Varying& input, A&&... args) { + auto model = std::make_shared(name, input, std::make_shared()); + { + Duration profileRange(trace_render(), ("build::" + model->getName()).c_str()); + model->_data.build(*(model), model->_input, model->_output, std::forward(args)...); + } // Recreate the Config to use the templated type model->createConfiguration(); model->applyConfiguration(); @@ -302,9 +306,9 @@ public: } template - static std::shared_ptr create(A&&... args) { + static std::shared_ptr create(const std::string& name, A&&... args) { const auto input = Varying(Input()); - return create(input, std::forward(args)...); + return create(name, input, std::forward(args)...); } void createConfiguration() { @@ -326,6 +330,7 @@ public: } void applyConfiguration() override { + Duration profileRange(trace_render(), ("configure::" + JobConcept::getName()).c_str()); jobConfigure(_data, *std::static_pointer_cast(Concept::_config)); for (auto& job : TaskConcept::_jobs) { job.applyConfiguration(); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 7a938f39c8..a1d09139e3 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -154,6 +154,13 @@ void OffscreenUi::show(const QUrl& url, const QString& name, std::function f) { QQuickItem* item = getRootItem()->findChild(name); if (!item) { diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index cb8ee29068..26f9f58dd5 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -60,6 +60,7 @@ public: void createDesktop(const QUrl& url); void show(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); void hide(const QString& name); + void hideDesktopWindows(); bool isVisible(const QString& name); void toggle(const QUrl& url, const QString& name, std::function f = [](QQmlContext*, QObject*) {}); bool shouldSwallowShortcut(QEvent* event); diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 12e9b8b87c..cfff0405c0 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -256,6 +256,15 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) { #if !defined(Q_OS_ANDROID) rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext)); rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext)); + { + PROFILE_RANGE(startup, "FileTypeProfile"); + rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext)); + } + { + PROFILE_RANGE(startup, "HFWebEngineProfile"); + rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext)); + + } #endif rootContext->setContextProperty("Paths", DependencyManager::get().data()); rootContext->setContextProperty("Tablet", DependencyManager::get().data()); diff --git a/libraries/ui/src/ui/OffscreenQmlSurfaceCache.cpp b/libraries/ui/src/ui/OffscreenQmlSurfaceCache.cpp index 7efa36624b..51fe11fdc7 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurfaceCache.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurfaceCache.cpp @@ -12,6 +12,7 @@ #include #include "OffscreenQmlSurface.h" +#include "Profile.h" OffscreenQmlSurfaceCache::OffscreenQmlSurfaceCache() { } @@ -38,6 +39,7 @@ void OffscreenQmlSurfaceCache::reserve(const QString& rootSource, int count) { } void OffscreenQmlSurfaceCache::release(const QString& rootSource, const QSharedPointer& surface) { + PROFILE_RANGE(app, "buildSurface"); surface->pause(); _cache[rootSource].push_back(surface); } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 0191baca5e..a079609bb7 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -387,6 +387,8 @@ void TabletProxy::setToolbarMode(bool toolbarMode) { offscreenUi->hide("RunningScripts"); _showRunningScripts = true; } + + offscreenUi->hideDesktopWindows(); // destroy desktop window if (_desktopWindow) { _desktopWindow->deleteLater(); diff --git a/script-archive/example/audio/audioReverbOn.js b/script-archive/example/audio/audioReverbOn.js deleted file mode 100644 index 72f2fa97bc..0000000000 --- a/script-archive/example/audio/audioReverbOn.js +++ /dev/null @@ -1,43 +0,0 @@ -// -// audioReverbOn.js -// examples -// -// Copyright 2014 High Fidelity, Inc. -// -// -// Gives the ability to be set various reverb settings. -// -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -// http://wiki.audacityteam.org/wiki/GVerb#Instant_reverb_settings -var audioOptions = new AudioEffectOptions({ - // Square Meters - maxRoomSize: 50, - roomSize: 50, - - // Seconds - reverbTime: 10, - - // Between 0 - 1 - damping: 0.50, - inputBandwidth: 0.75, - - // dB - earlyLevel: -22, - tailLevel: -28, - dryLevel: 0, - wetLevel: 6 -}); - -AudioDevice.setReverbOptions(audioOptions); -AudioDevice.setReverb(true); -print("Reverb is now on with the updated options."); - -function scriptEnding() { - AudioDevice.setReverb(false); - print("Reberb is now off."); -} - -Script.scriptEnding.connect(scriptEnding); \ No newline at end of file diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 1171703847..776fd11e5c 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -8,7 +8,7 @@ // // Grab's physically moveable entities with the mouse, by applying a spring force. // -// Updated November 22, 2016 by Philip Rosedale: Add distance attenuation of grab effect +// Updated November 22, 2016 by Philip Rosedale: Add distance attenuation of grab effect // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -444,6 +444,7 @@ Grabber.prototype.releaseEvent = function(event) { this.actionID = null; Pointers.setRenderState(this.mouseRayEntities, ""); + Pointers.setLockEndUUID(this.mouseRayEntities, null, false); var args = "mouse"; Entities.callEntityMethod(this.entityID, "releaseGrab", args); diff --git a/scripts/system/edit.js b/scripts/system/edit.js index ea22359805..fd7a488eb7 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -416,6 +416,12 @@ var toolBar = (function () { // default: // shapeType = "uv"; //} + var materialData = ""; + if (materialURL.startsWith("materialData")) { + materialData = JSON.stringify({ + "materials": {} + }) + } var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1; if (materialURL) { @@ -423,7 +429,8 @@ var toolBar = (function () { type: "Material", materialURL: materialURL, //materialMappingMode: materialMappingMode, - priority: DEFAULT_LAYERED_MATERIAL_PRIORITY + priority: DEFAULT_LAYERED_MATERIAL_PRIORITY, + materialData: materialData }); } } @@ -2061,7 +2068,7 @@ var PropertiesTool = function (opts) { parentSelectedEntities(); } else if (data.type === 'unparent') { unparentSelectedEntities(); - } else if (data.type === 'saveUserData') { + } else if (data.type === 'saveUserData' || data.type === 'saveMaterialData') { //the event bridge and json parsing handle our avatar id string differently. var actualID = data.id.split('"')[1]; Entities.editEntity(actualID, data.properties); diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 7664ae8714..6c1931932a 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -1387,12 +1387,14 @@ input#reset-to-natural-dimensions { margin-top: 48px; } -#userdata-clear{ +#userdata-clear, +#materialdata-clear { margin-bottom: 10px; } -#static-userdata { +#static-userdata, +#static-materialData { display: none; z-index: 99; position: absolute; @@ -1403,7 +1405,8 @@ input#reset-to-natural-dimensions { background-color: #2e2e2e; } -#userdata-saved { +#userdata-saved, +#materialData-saved { margin-top:5px; font-size:16px; display:none; diff --git a/scripts/system/html/entityProperties.html b/scripts/system/html/entityProperties.html index 82a450bedd..8647dca035 100644 --- a/scripts/system/html/entityProperties.html +++ b/scripts/system/html/entityProperties.html @@ -781,6 +781,20 @@ + +
+ +

+
+ + + + Saved! +
+
+
+ +
diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index d2fa2eeeb0..4b6329db44 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -66,6 +66,7 @@ function enableProperties() { if (elLocked.checked === false) { removeStaticUserData(); + removeStaticMaterialData(); } } @@ -78,8 +79,13 @@ function disableProperties() { } var elLocked = document.getElementById("property-locked"); - if ($('#userdata-editor').css('display') === "block" && elLocked.checked === true) { - showStaticUserData(); + if (elLocked.checked === true) { + if ($('#userdata-editor').css('display') === "block") { + showStaticUserData(); + } + if ($('#materialdata-editor').css('display') === "block") { + showStaticMaterialData(); + } } } @@ -356,15 +362,139 @@ function userDataChanger(groupName, keyName, values, userDataElement, defaultVal multiDataUpdater(groupName, val, userDataElement, def); } +function setMaterialDataFromEditor(noUpdate) { + var json = null; + try { + json = materialEditor.get(); + } catch (e) { + alert('Invalid JSON code - look for red X in your code ', +e); + } + if (json === null) { + return; + } else { + var text = materialEditor.getText(); + if (noUpdate === true) { + EventBridge.emitWebEvent( + JSON.stringify({ + id: lastEntityID, + type: "saveMaterialData", + properties: { + materialData: text + } + }) + ); + return; + } else { + updateProperty('materialData', text); + } + } +} + function setTextareaScrolling(element) { var isScrolling = element.scrollHeight > element.offsetHeight; element.setAttribute("scrolling", isScrolling ? "true" : "false"); } +var materialEditor = null; + +function createJSONMaterialEditor() { + var container = document.getElementById("materialdata-editor"); + var options = { + search: false, + mode: 'tree', + modes: ['code', 'tree'], + name: 'materialData', + onModeChange: function() { + $('.jsoneditor-poweredBy').remove(); + }, + onError: function(e) { + alert('JSON editor:' + e); + }, + onChange: function() { + var currentJSONString = materialEditor.getText(); + + if (currentJSONString === '{"":""}') { + return; + } + $('#materialdata-save').attr('disabled', false); + + + } + }; + materialEditor = new JSONEditor(container, options); +} + +function hideNewJSONMaterialEditorButton() { + $('#materialdata-new-editor').hide(); +} + +function showSaveMaterialDataButton() { + $('#materialdata-save').show(); +} + +function hideSaveMaterialDataButton() { + $('#materialdata-save').hide(); +} + +function showNewJSONMaterialEditorButton() { + $('#materialdata-new-editor').show(); +} + +function showMaterialDataTextArea() { + $('#property-material-data').show(); +} + +function hideMaterialDataTextArea() { + $('#property-material-data').hide(); +} + +function showStaticMaterialData() { + if (materialEditor !== null) { + $('#static-materialdata').show(); + $('#static-materialdata').css('height', $('#materialdata-editor').height()); + $('#static-materialdata').text(materialEditor.getText()); + } +} + +function removeStaticMaterialData() { + $('#static-materialdata').hide(); +} + +function setMaterialEditorJSON(json) { + materialEditor.set(json); + if (materialEditor.hasOwnProperty('expandAll')) { + materialEditor.expandAll(); + } +} + +function getMaterialEditorJSON() { + return materialEditor.get(); +} + +function deleteJSONMaterialEditor() { + if (materialEditor !== null) { + materialEditor.destroy(); + materialEditor = null; + } +} + +var savedMaterialJSONTimer = null; + +function saveJSONMaterialData(noUpdate) { + setMaterialDataFromEditor(noUpdate); + $('#materialdata-saved').show(); + $('#materialdata-save').attr('disabled', true); + if (savedMaterialJSONTimer !== null) { + clearTimeout(savedMaterialJSONTimer); + } + savedMaterialJSONTimer = setTimeout(function() { + $('#materialdata-saved').hide(); + + }, EDITOR_TIMEOUT_DURATION); +} + var editor = null; -var editorTimeout = null; -var lastJSONString = null; function createJSONEditor() { var container = document.getElementById("userdata-editor"); @@ -395,11 +525,6 @@ function createJSONEditor() { function hideNewJSONEditorButton() { $('#userdata-new-editor').hide(); - -} - -function hideClearUserDataButton() { - $('#userdata-clear').hide(); } function showSaveUserDataButton() { @@ -408,17 +533,10 @@ function showSaveUserDataButton() { function hideSaveUserDataButton() { $('#userdata-save').hide(); - } function showNewJSONEditorButton() { $('#userdata-new-editor').show(); - -} - -function showClearUserDataButton() { - $('#userdata-clear').show(); - } function showUserDataTextArea() { @@ -446,7 +564,6 @@ function setEditorJSON(json) { if (editor.hasOwnProperty('expandAll')) { editor.expandAll(); } - } function getEditorJSON() { @@ -484,12 +601,15 @@ function bindAllNonJSONEditorElements() { // TODO FIXME: (JSHint) Functions declared within loops referencing // an outer scoped variable may lead to confusing semantics. field.on('focus', function(e) { - if (e.target.id === "userdata-new-editor" || e.target.id === "userdata-clear") { + if (e.target.id === "userdata-new-editor" || e.target.id === "userdata-clear" || e.target.id === "materialdata-new-editor" || e.target.id === "materialdata-clear") { return; } else { if ($('#userdata-editor').css('height') !== "0px") { saveJSONUserData(true); } + if ($('#materialdata-editor').css('height') !== "0px") { + saveJSONMaterialData(true); + } } }); } @@ -652,6 +772,10 @@ function loaded() { var elMaterialMappingScaleX = document.getElementById("property-material-mapping-scale-x"); var elMaterialMappingScaleY = document.getElementById("property-material-mapping-scale-y"); var elMaterialMappingRot = document.getElementById("property-material-mapping-rot"); + var elMaterialData = document.getElementById("property-material-data"); + var elClearMaterialData = document.getElementById("materialdata-clear"); + var elSaveMaterialData = document.getElementById("materialdata-save"); + var elNewJSONMaterialEditor = document.getElementById('materialdata-new-editor'); var elImageURL = document.getElementById("property-image-url"); @@ -772,9 +896,15 @@ function loaded() { } else if (data.type === "update") { if (!data.selections || data.selections.length === 0) { - if (editor !== null && lastEntityID !== null) { - saveJSONUserData(true); - deleteJSONEditor(); + if (lastEntityID !== null) { + if (editor !== null) { + saveJSONUserData(true); + deleteJSONEditor(); + } + if (materialEditor !== null) { + saveJSONMaterialData(true); + deleteJSONMaterialEditor(); + } } elTypeIcon.style.display = "none"; elType.innerHTML = "No selection"; @@ -783,6 +913,7 @@ function loaded() { disableProperties(); } else if (data.selections && data.selections.length > 1) { deleteJSONEditor(); + deleteJSONMaterialEditor(); var selections = data.selections; var ids = []; @@ -815,8 +946,13 @@ function loaded() { } else { properties = data.selections[0].properties; - if (lastEntityID !== '"' + properties.id + '"' && lastEntityID !== null && editor !== null) { - saveJSONUserData(true); + if (lastEntityID !== '"' + properties.id + '"' && lastEntityID !== null) { + if (editor !== null) { + saveJSONUserData(true); + } + if (materialEditor !== null) { + saveJSONMaterialData(true); + } } var doSelectElement = lastEntityID === '"' + properties.id + '"'; @@ -993,6 +1129,28 @@ function loaded() { hideNewJSONEditorButton(); } + var materialJson = null; + try { + materialJson = JSON.parse(properties.materialData); + } catch (e) { + // normal text + deleteJSONMaterialEditor(); + elMaterialData.value = properties.materialData; + showMaterialDataTextArea(); + showNewJSONMaterialEditorButton(); + hideSaveMaterialDataButton(); + } + if (materialJson !== null) { + if (materialEditor === null) { + createJSONMaterialEditor(); + } + + setMaterialEditorJSON(materialJson); + showSaveMaterialDataButton(); + hideMaterialDataTextArea(); + hideNewJSONMaterialEditorButton(); + } + elHyperlinkHref.value = properties.href; elDescription.value = properties.description; @@ -1200,6 +1358,7 @@ function loaded() { } else { enableProperties(); elSaveUserData.disabled = true; + elSaveMaterialData.disabled = true; } var activeElement = document.activeElement; @@ -1384,6 +1543,31 @@ function loaded() { showSaveUserDataButton(); }); + elClearMaterialData.addEventListener("click", function() { + deleteJSONMaterialEditor(); + elMaterialData.value = ""; + showMaterialDataTextArea(); + showNewJSONMaterialEditorButton(); + hideSaveMaterialDataButton(); + updateProperty('materialData', elMaterialData.value); + }); + + elSaveMaterialData.addEventListener("click", function() { + saveJSONMaterialData(true); + }); + + elMaterialData.addEventListener('change', createEmitTextPropertyUpdateFunction('materialData')); + + elNewJSONMaterialEditor.addEventListener('click', function() { + deleteJSONMaterialEditor(); + createJSONMaterialEditor(); + var data = {}; + setMaterialEditorJSON(data); + hideMaterialDataTextArea(); + hideNewJSONMaterialEditorButton(); + showSaveMaterialDataButton(); + }); + var colorChangeFunction = createEmitColorPropertyUpdateFunction( 'color', elColorRed, elColorGreen, elColorBlue); elColorRed.addEventListener('change', colorChangeFunction); diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 70456ea493..9c994ed2ea 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -12,9 +12,9 @@ Script.include("/~/system/libraries/utils.js"); if (!String.prototype.startsWith) { String.prototype.startsWith = function(searchString, position){ - position = position || 0; - return this.substr(position, searchString.length) === searchString; - }; + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; } var SETTING_KEY = "com.highfidelity.avatar.isSitting"; @@ -122,20 +122,10 @@ this.rolesToOverride = function() { return MyAvatar.getAnimationRoles().filter(function(role) { - return !(role.startsWith("right") || role.startsWith("left")); + return !(role.startsWith("right") || role.startsWith("left")); }); } - // Handler for user changing the avatar model while sitting. There's currently an issue with changing avatar models while override role animations are applied, - // so to avoid that problem, re-apply the role overrides once the model has finished changing. - this.modelURLChangeFinished = function () { - print("Sitter's model has FINISHED changing. Reapply anim role overrides."); - var roles = this.rolesToOverride(); - for (i in roles) { - MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); - } - } - this.sitDown = function() { if (this.checkSeatForAvatar()) { print("Someone is already sitting in that chair."); @@ -155,11 +145,11 @@ MyAvatar.characterControllerEnabled = false; MyAvatar.hmdLeanRecenterEnabled = false; var roles = this.rolesToOverride(); - for (i in roles) { + for (var i = 0; i < roles.length; i++) { MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); } - for (var i in OVERRIDEN_DRIVE_KEYS) { + for (i = 0; i < OVERRIDEN_DRIVE_KEYS.length; i++) { MyAvatar.disableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); } @@ -174,14 +164,12 @@ return { headType: 0 }; }, ["headType"]); Script.update.connect(this, this.update); - MyAvatar.onLoadComplete.connect(this, this.modelURLChangeFinished); } this.standUp = function() { print("Standing up (" + this.entityID + ")"); MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); - MyAvatar.onLoadComplete.disconnect(this, this.modelURLChangeFinished); if (MyAvatar.sessionUUID === this.getSeatUser()) { this.setSeatUser(null); @@ -190,12 +178,12 @@ if (Settings.getValue(SETTING_KEY) === this.entityID) { Settings.setValue(SETTING_KEY, ""); - for (var i in OVERRIDEN_DRIVE_KEYS) { + for (var i = 0; i < OVERRIDEN_DRIVE_KEYS.length; i++) { MyAvatar.enableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); } var roles = this.rolesToOverride(); - for (i in roles) { + for (i = 0; i < roles.length; i++) { MyAvatar.restoreRoleAnimation(roles[i]); } MyAvatar.characterControllerEnabled = true; @@ -272,7 +260,7 @@ // Check if a drive key is pressed var hasActiveDriveKey = false; for (var i in OVERRIDEN_DRIVE_KEYS) { - if (MyAvatar.getRawDriveKey(OVERRIDEN_DRIVE_KEYS[i]) != 0.0) { + if (MyAvatar.getRawDriveKey(OVERRIDEN_DRIVE_KEYS[i]) !== 0.0) { hasActiveDriveKey = true; break; } @@ -343,7 +331,7 @@ } this.cleanupOverlay(); } - + this.clickDownOnEntity = function (id, event) { if (isInEditMode()) { return; @@ -352,4 +340,4 @@ this.sitDown(); } } -}); +}); \ No newline at end of file diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 5d8b9115b8..99f9025fdd 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -304,7 +304,7 @@ void Test::createRecursiveScript() { } // This method creates a `testRecursive.js` script in every sub-folder. -void Test::createRecursiveScriptsRecursively() { +void Test::createAllRecursiveScripts() { // Select folder to start recursing from QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the recursive scripts", ".", QFileDialog::ShowDirsOnly); if (topLevelDirectory == "") { @@ -559,6 +559,44 @@ void Test::createMDFile() { return; } + createMDFile(testDirectory); +} + +void Test::createAllMDFiles() { + // Select folder to start recursing from + QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the MD files", ".", QFileDialog::ShowDirsOnly); + if (topLevelDirectory == "") { + return; + } + + // First test if top-level folder has a test.js file + const QString testPathname{ topLevelDirectory + "/" + TEST_FILENAME }; + QFileInfo fileInfo(testPathname); + if (fileInfo.exists()) { + createMDFile(topLevelDirectory); + } + + QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it.hasNext()) { + QString directory = it.next(); + + // Only process directories + QDir dir; + if (!isAValidDirectory(directory)) { + continue; + } + + const QString testPathname{ directory + "/" + TEST_FILENAME }; + QFileInfo fileInfo(testPathname); + if (fileInfo.exists()) { + createMDFile(directory); + } + } + + messageBox.information(0, "Success", "MD files have been created"); +} + +void Test::createMDFile(QString testDirectory) { // Verify folder contains test.js file QString testFileName(testDirectory + "/" + TEST_FILENAME); QFileInfo testFileInfo(testFileName); @@ -639,8 +677,8 @@ void Test::createMDFile() { int snapShotIndex { 0 }; for (size_t i = 0; i < testScriptLines.stepList.size(); ++i) { - stream << "### Step " << QString::number(i) << "\n"; - stream << "- " << testScriptLines.stepList[i + 1]->text << "\n"; + stream << "### Step " << QString::number(i + 1) << "\n"; + stream << "- " << testScriptLines.stepList[i]->text << "\n"; if (testScriptLines.stepList[i]->takeSnapshot) { stream << "- ![](./ExpectedImage_" << QString::number(snapShotIndex).rightJustified(5, '0') << ".png)\n"; ++snapShotIndex; @@ -650,6 +688,77 @@ void Test::createMDFile() { mdFile.close(); } +void Test::createTestsOutline() { + QString testsRootDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the tests root folder", ".", QFileDialog::ShowDirsOnly); + if (testsRootDirectory == "") { + return; + } + + const QString testsOutlineFilename { "testsOutline.md" }; + QString mdFilename(testsRootDirectory + "/" + testsOutlineFilename); + QFile mdFile(mdFilename); + if (!mdFile.open(QIODevice::WriteOnly)) { + messageBox.critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename); + exit(-1); + } + + QTextStream stream(&mdFile); + + //Test title + stream << "# Outline of all tests\n"; + stream << "Directories with an appended (*) have an automatic test\n\n"; + + // We need to know our current depth, as this isn't given by QDirIterator + int rootDepth { testsRootDirectory.count('/') }; + + // Each test is shown as the folder name linking to the matching GitHub URL, and the path to the associated test.md file + QDirIterator it(testsRootDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it.hasNext()) { + QString directory = it.next(); + + // Only process directories + QDir dir; + if (!isAValidDirectory(directory)) { + continue; + } + + // Ignore the utils directory + if (directory.right(5) == "utils") { + continue; + } + + // The prefix is the MarkDown prefix needed for correct indentation + // It consists of 2 spaces for each level of indentation, folled by a dash sign + int currentDepth = directory.count('/') - rootDepth; + QString prefix = QString(" ").repeated(2 * currentDepth - 1) + " - "; + + // The directory name appears after the last slash (we are assured there is at least 1). + QString directoryName = directory.right(directory.length() - directory.lastIndexOf("/") - 1); + + // autoTester is run on a clone of the repository. We use relative paths, so we can use both local disk and GitHub + // For a test in "D:/GitHub/hifi_tests/tests/content/entity/zone/ambientLightInheritance" the + // GitHub URL is "./content/entity/zone/ambientLightInheritance?raw=true" + QString partialPath = directory.right(directory.length() - (directory.lastIndexOf("/tests/") + QString("/tests").length() + 1)); + QString url = "./" + partialPath; + + stream << prefix << "[" << directoryName << "](" << url << "?raw=true" << ")"; + QFileInfo fileInfo1(directory + "/test.md"); + if (fileInfo1.exists()) { + stream << " [(test description)](" << url << "/test.md)"; + } + + QFileInfo fileInfo2(directory + "/" + TEST_FILENAME); + if (fileInfo2.exists()) { + stream << " (*)"; + } + stream << "\n"; + } + + mdFile.close(); + + messageBox.information(0, "Success", "Test outline file " + testsOutlineFilename + " has been created"); +} + void Test::copyJPGtoPNG(QString sourceJPGFullFilename, QString destinationPNGFullFilename) { QFile::remove(destinationPNGFullFilename); diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 3d04b00df9..e69459fef2 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -45,11 +45,15 @@ public: void finishTestsEvaluation(bool interactiveMode, QProgressBar* progressBar); void createRecursiveScript(); - void createRecursiveScriptsRecursively(); + void createAllRecursiveScripts(); void createRecursiveScript(QString topLevelDirectory, bool interactiveMode); void createTest(); void createMDFile(); + void createAllMDFiles(); + void createMDFile(QString topLevelDirectory); + + void createTestsOutline(); bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 9153365184..21acfe9569 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -28,8 +28,8 @@ void AutoTester::on_createRecursiveScriptButton_clicked() { test->createRecursiveScript(); } -void AutoTester::on_createRecursiveScriptsRecursivelyButton_clicked() { - test->createRecursiveScriptsRecursively(); +void AutoTester::on_createAllRecursiveScriptsButton_clicked() { + test->createAllRecursiveScripts(); } void AutoTester::on_createTestButton_clicked() { @@ -37,7 +37,15 @@ void AutoTester::on_createTestButton_clicked() { } void AutoTester::on_createMDFileButton_clicked() { - test->createMDFile(); + test->createMDFile(); +} + +void AutoTester::on_createAllMDFilesButton_clicked() { + test->createAllMDFiles(); +} + +void AutoTester::on_createTestsOutlineButton_clicked() { + test->createTestsOutline(); } void AutoTester::on_closeButton_clicked() { diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 82ff3780e3..1788e97177 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -28,10 +28,12 @@ public: private slots: void on_evaluateTestsButton_clicked(); void on_createRecursiveScriptButton_clicked(); - void on_createRecursiveScriptsRecursivelyButton_clicked(); + void on_createAllRecursiveScriptsButton_clicked(); void on_createTestButton_clicked(); - void on_createMDFileButton_clicked(); - void on_closeButton_clicked(); + void on_createMDFileButton_clicked(); + void on_createAllMDFilesButton_clicked(); + void on_createTestsOutlineButton_clicked(); + void on_closeButton_clicked(); void saveImage(int index); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index 600de283ad..2eb1314481 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -17,8 +17,8 @@ - 20 - 420 + 360 + 400 220 40 @@ -44,7 +44,7 @@ 20 - 255 + 285 220 40 @@ -57,7 +57,7 @@ 360 - 75 + 35 220 40 @@ -70,7 +70,7 @@ 23 - 220 + 250 131 20 @@ -86,7 +86,7 @@ 20 - 310 + 340 255 23 @@ -99,20 +99,20 @@ 360 - 140 + 100 220 40 - Create Recursive Scripts Recursively + Create all Recursive Scripts 20 - 90 + 80 220 40 @@ -121,6 +121,32 @@ Create MD file + + + + 20 + 130 + 220 + 40 + + + + Create all MD files + + + + + + 20 + 180 + 220 + 40 + + + + Create Tests Outline + + diff --git a/tools/bake-tools/bake.py b/tools/bake-tools/bake.py index cad638c911..edbfdf9e9f 100644 --- a/tools/bake-tools/bake.py +++ b/tools/bake-tools/bake.py @@ -44,26 +44,35 @@ def groupKTXFiles(directory, filePath): originalFilePath.strip() shutil.move(originalFilePath, newFilePath) -def bakeFile(filePath, outputDirectory): +def bakeFile(filePath, outputDirectory, fileType): createDirectory(outputDirectory) - cmd = EXE + ' -i ' + filePath + ' -o ' + outputDirectory + ' -t fbx' + cmd = EXE + ' -i ' + filePath + ' -o ' + outputDirectory + ' -t ' + fileType args = shlex.split(cmd) process = subprocess.Popen(cmd, stdout=False, stderr=False) process.wait() bakedFile = os.path.splitext(filePath)[0] - groupKTXFiles(outputDirectory, bakedFile) + if fileType == 'fbx': + groupKTXFiles(outputDirectory, bakedFile) def bakeFilesInDirectory(directory, outputDirectory): rootDirectory = os.path.basename(os.path.normpath(directory)) for root, subFolders, filenames in os.walk(directory): for filename in filenames: appendPath = getRelativePath(directory, root, rootDirectory); + name, ext = os.path.splitext('file.txt') if filename.endswith('.fbx'): filePath = os.sep.join([root, filename]) absFilePath = os.path.abspath(filePath) outputFolder = os.path.join(outputDirectory, appendPath) print "Baking file: " + filename - bakeFile(absFilePath, outputFolder) + bakeFile(absFilePath, outputFolder, 'fbx') + elif os.path.basename(root) == 'skyboxes': + filePath = os.sep.join([root, filename]) + absFilePath = os.path.abspath(filePath) + outputFolder = os.path.join(outputDirectory, appendPath) + print "Baking file: " + filename + bakeType = os.path.splitext(filename)[1][1:] + bakeFile(absFilePath, outputFolder, bakeType) else: filePath = os.sep.join([root, filename]) absFilePath = os.path.abspath(filePath) diff --git a/tools/bake-tools/convertToRelativePaths.py b/tools/bake-tools/convertToRelativePaths.py index 27a7b7ac02..70a6a30cfb 100644 --- a/tools/bake-tools/convertToRelativePaths.py +++ b/tools/bake-tools/convertToRelativePaths.py @@ -6,7 +6,7 @@ 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'): + if not filename.endswith('.ktx') or os.path.basename(root) == 'skyboxes': substring = os.path.commonprefix([assetDirectory, root]) newPath = root.replace(substring, ''); filePath = os.sep.join([newPath, filename]) @@ -30,7 +30,7 @@ def handleURL(url): baseFilename = os.path.basename(url) filename = os.path.splitext(baseFilename)[0] newUrl = MAP[filename] - print newUrl + print url + ' -> ' + newUrl return newUrl def handleOptions(): @@ -43,8 +43,12 @@ def main(): argsLength = len(sys.argv) if argsLength == 3: jsonFile = sys.argv[1] - gzipFile = jsonFile + '.gz' assetDirectory = sys.argv[2] + inputFilename = os.path.basename(jsonFile); + absPath = os.path.abspath(assetDirectory) + finalPath = absPath.replace('\\', '/'); + gzipFile = finalPath + '/' + inputFilename + '.gz' + print gzipFile createAssetMapping(assetDirectory) f = open(jsonFile) data = json.load(f) @@ -65,6 +69,15 @@ def main(): except: value = handleURL(value) + + if prop == "ambientLight": + for index in value: + value[index] = handleURL(value[index]) + + if prop == "skybox": + for index in value: + value[index] = handleURL(value[index]) + if prop == "serverScripts": value = handleURL(value)